@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.
- package/CHANGELOG.md +164 -0
- package/ENDOFFILE +0 -0
- package/EOF +0 -0
- package/LICENSE +21 -0
- package/SPEC-SUPPORT.md +116 -0
- package/YAMLEND +0 -0
- package/api.ts +18 -0
- package/archipelagolab-lobi-1.0.0.tgz +0 -0
- package/auth-presence.ts +56 -0
- package/channel-plugin-api.ts +3 -0
- package/cli-metadata.ts +11 -0
- package/contract-api.ts +17 -0
- package/docs/CHECKLIST.md +83 -0
- package/docs/FORK_SDK_GUIDE.md +279 -0
- package/helper-api.ts +3 -0
- package/index.test.ts +61 -0
- package/index.ts +65 -0
- package/openclaw.plugin.json +23 -0
- package/package.json +52 -0
- package/plugin-entry.handlers.runtime.ts +1 -0
- package/runtime-api.ts +54 -0
- package/runtime-heavy-api.ts +1 -0
- package/scripts/migrate-to-lobi.sh +72 -0
- package/secret-contract-api.ts +5 -0
- package/setup-entry.ts +13 -0
- package/src/account-selection.test.ts +124 -0
- package/src/account-selection.ts +226 -0
- package/src/actions.account-propagation.test.ts +251 -0
- package/src/actions.test.ts +251 -0
- package/src/actions.ts +336 -0
- package/src/approval-auth.test.ts +23 -0
- package/src/approval-auth.ts +25 -0
- package/src/approval-handler.runtime.test.ts +46 -0
- package/src/approval-handler.runtime.ts +400 -0
- package/src/approval-ids.ts +6 -0
- package/src/approval-native.test.ts +329 -0
- package/src/approval-native.ts +336 -0
- package/src/approval-reactions.test.ts +107 -0
- package/src/approval-reactions.ts +158 -0
- package/src/auth-precedence.ts +61 -0
- package/src/channel-account-paths.ts +92 -0
- package/src/channel.account-paths.test.ts +102 -0
- package/src/channel.directory.test.ts +601 -0
- package/src/channel.resolve.test.ts +38 -0
- package/src/channel.runtime.ts +16 -0
- package/src/channel.setup.test.ts +269 -0
- package/src/channel.ts +570 -0
- package/src/cli-metadata.ts +19 -0
- package/src/cli.test.ts +1015 -0
- package/src/cli.ts +1198 -0
- package/src/config-adapter.ts +41 -0
- package/src/config-schema.test.ts +90 -0
- package/src/config-schema.ts +114 -0
- package/src/directory-live.test.ts +200 -0
- package/src/directory-live.ts +238 -0
- package/src/doctor-contract.ts +287 -0
- package/src/doctor.test.ts +440 -0
- package/src/doctor.ts +262 -0
- package/src/env-vars.ts +92 -0
- package/src/exec-approval-resolver.test.ts +68 -0
- package/src/exec-approval-resolver.ts +23 -0
- package/src/exec-approvals.test.ts +483 -0
- package/src/exec-approvals.ts +290 -0
- package/src/group-mentions.ts +41 -0
- package/src/legacy-crypto-inspector-availability.test.ts +81 -0
- package/src/legacy-crypto-inspector-availability.ts +60 -0
- package/src/legacy-crypto.test.ts +234 -0
- package/src/legacy-crypto.ts +549 -0
- package/src/legacy-state.test.ts +86 -0
- package/src/legacy-state.ts +156 -0
- package/src/matrix/account-config.ts +150 -0
- package/src/matrix/accounts.readiness.test.ts +27 -0
- package/src/matrix/accounts.test.ts +757 -0
- package/src/matrix/accounts.ts +194 -0
- package/src/matrix/actions/client.test.ts +215 -0
- package/src/matrix/actions/client.ts +31 -0
- package/src/matrix/actions/devices.test.ts +114 -0
- package/src/matrix/actions/devices.ts +34 -0
- package/src/matrix/actions/limits.test.ts +15 -0
- package/src/matrix/actions/limits.ts +6 -0
- package/src/matrix/actions/messages.test.ts +289 -0
- package/src/matrix/actions/messages.ts +123 -0
- package/src/matrix/actions/pins.test.ts +74 -0
- package/src/matrix/actions/pins.ts +64 -0
- package/src/matrix/actions/polls.test.ts +71 -0
- package/src/matrix/actions/polls.ts +109 -0
- package/src/matrix/actions/profile.test.ts +109 -0
- package/src/matrix/actions/profile.ts +37 -0
- package/src/matrix/actions/reactions.test.ts +135 -0
- package/src/matrix/actions/reactions.ts +59 -0
- package/src/matrix/actions/room.test.ts +79 -0
- package/src/matrix/actions/room.ts +71 -0
- package/src/matrix/actions/summary.test.ts +87 -0
- package/src/matrix/actions/summary.ts +88 -0
- package/src/matrix/actions/types.ts +82 -0
- package/src/matrix/actions/verification.test.ts +105 -0
- package/src/matrix/actions/verification.ts +237 -0
- package/src/matrix/actions.ts +37 -0
- package/src/matrix/active-client.ts +26 -0
- package/src/matrix/async-lock.ts +18 -0
- package/src/matrix/backup-health.ts +115 -0
- package/src/matrix/client/config-runtime-api.ts +14 -0
- package/src/matrix/client/config-secret-input.runtime.ts +1 -0
- package/src/matrix/client/config.ts +982 -0
- package/src/matrix/client/create-client.test.ts +115 -0
- package/src/matrix/client/create-client.ts +101 -0
- package/src/matrix/client/env-auth.ts +6 -0
- package/src/matrix/client/file-sync-store.test.ts +265 -0
- package/src/matrix/client/file-sync-store.ts +289 -0
- package/src/matrix/client/logging.ts +123 -0
- package/src/matrix/client/migration-snapshot.runtime.ts +1 -0
- package/src/matrix/client/private-network-host.ts +56 -0
- package/src/matrix/client/runtime.ts +4 -0
- package/src/matrix/client/shared.test.ts +344 -0
- package/src/matrix/client/shared.ts +306 -0
- package/src/matrix/client/storage.test.ts +634 -0
- package/src/matrix/client/storage.ts +544 -0
- package/src/matrix/client/types.ts +50 -0
- package/src/matrix/client-bootstrap.test.ts +84 -0
- package/src/matrix/client-bootstrap.ts +164 -0
- package/src/matrix/client-resolver.test-helpers.ts +147 -0
- package/src/matrix/client.test.ts +1521 -0
- package/src/matrix/client.ts +23 -0
- package/src/matrix/config-paths.ts +31 -0
- package/src/matrix/config-update.test.ts +237 -0
- package/src/matrix/config-update.ts +291 -0
- package/src/matrix/credentials-read.ts +206 -0
- package/src/matrix/credentials-write.runtime.ts +26 -0
- package/src/matrix/credentials.test.ts +501 -0
- package/src/matrix/credentials.ts +95 -0
- package/src/matrix/deps.test.ts +74 -0
- package/src/matrix/deps.ts +225 -0
- package/src/matrix/device-health.test.ts +45 -0
- package/src/matrix/device-health.ts +31 -0
- package/src/matrix/direct-management.test.ts +350 -0
- package/src/matrix/direct-management.ts +347 -0
- package/src/matrix/direct-room.test.ts +61 -0
- package/src/matrix/direct-room.ts +128 -0
- package/src/matrix/draft-stream.test.ts +406 -0
- package/src/matrix/draft-stream.ts +216 -0
- package/src/matrix/encryption-guidance.ts +27 -0
- package/src/matrix/errors.ts +21 -0
- package/src/matrix/format.test.ts +340 -0
- package/src/matrix/format.ts +428 -0
- package/src/matrix/legacy-crypto-inspector.ts +95 -0
- package/src/matrix/media-errors.ts +20 -0
- package/src/matrix/media-text.ts +169 -0
- package/src/matrix/monitor/access-state.test.ts +45 -0
- package/src/matrix/monitor/access-state.ts +77 -0
- package/src/matrix/monitor/ack-config.test.ts +57 -0
- package/src/matrix/monitor/ack-config.ts +26 -0
- package/src/matrix/monitor/allowlist.test.ts +45 -0
- package/src/matrix/monitor/allowlist.ts +94 -0
- package/src/matrix/monitor/auto-join.test.ts +203 -0
- package/src/matrix/monitor/auto-join.ts +86 -0
- package/src/matrix/monitor/config.test.ts +197 -0
- package/src/matrix/monitor/config.ts +303 -0
- package/src/matrix/monitor/context-summary.ts +43 -0
- package/src/matrix/monitor/direct.test.ts +529 -0
- package/src/matrix/monitor/direct.ts +270 -0
- package/src/matrix/monitor/events.test.ts +1524 -0
- package/src/matrix/monitor/events.ts +213 -0
- package/src/matrix/monitor/handler.body-for-agent.test.ts +396 -0
- package/src/matrix/monitor/handler.group-history.test.ts +648 -0
- package/src/matrix/monitor/handler.media-failure.test.ts +267 -0
- package/src/matrix/monitor/handler.test-helpers.ts +308 -0
- package/src/matrix/monitor/handler.test.ts +2952 -0
- package/src/matrix/monitor/handler.thread-root-media.test.ts +82 -0
- package/src/matrix/monitor/handler.ts +1679 -0
- package/src/matrix/monitor/inbound-dedupe.test.ts +146 -0
- package/src/matrix/monitor/inbound-dedupe.ts +267 -0
- package/src/matrix/monitor/index.test.ts +920 -0
- package/src/matrix/monitor/index.ts +434 -0
- package/src/matrix/monitor/legacy-crypto-restore.test.ts +206 -0
- package/src/matrix/monitor/legacy-crypto-restore.ts +139 -0
- package/src/matrix/monitor/location.ts +100 -0
- package/src/matrix/monitor/media.test.ts +159 -0
- package/src/matrix/monitor/media.ts +119 -0
- package/src/matrix/monitor/mentions.test.ts +289 -0
- package/src/matrix/monitor/mentions.ts +177 -0
- package/src/matrix/monitor/reaction-events.test.ts +326 -0
- package/src/matrix/monitor/reaction-events.ts +187 -0
- package/src/matrix/monitor/recent-invite.test.ts +92 -0
- package/src/matrix/monitor/recent-invite.ts +30 -0
- package/src/matrix/monitor/replies.test.ts +265 -0
- package/src/matrix/monitor/replies.ts +136 -0
- package/src/matrix/monitor/reply-context.test.ts +276 -0
- package/src/matrix/monitor/reply-context.ts +92 -0
- package/src/matrix/monitor/room-history.test.ts +258 -0
- package/src/matrix/monitor/room-history.ts +301 -0
- package/src/matrix/monitor/room-info.test.ts +201 -0
- package/src/matrix/monitor/room-info.ts +126 -0
- package/src/matrix/monitor/rooms.test.ts +121 -0
- package/src/matrix/monitor/rooms.ts +52 -0
- package/src/matrix/monitor/route.test.ts +255 -0
- package/src/matrix/monitor/route.ts +178 -0
- package/src/matrix/monitor/runtime-api.ts +31 -0
- package/src/matrix/monitor/startup-verification.test.ts +294 -0
- package/src/matrix/monitor/startup-verification.ts +237 -0
- package/src/matrix/monitor/startup.test.ts +257 -0
- package/src/matrix/monitor/startup.ts +218 -0
- package/src/matrix/monitor/status.ts +111 -0
- package/src/matrix/monitor/sync-lifecycle.test.ts +224 -0
- package/src/matrix/monitor/sync-lifecycle.ts +91 -0
- package/src/matrix/monitor/task-runner.ts +38 -0
- package/src/matrix/monitor/thread-context.test.ts +149 -0
- package/src/matrix/monitor/thread-context.ts +108 -0
- package/src/matrix/monitor/threads.test.ts +68 -0
- package/src/matrix/monitor/threads.ts +85 -0
- package/src/matrix/monitor/types.ts +30 -0
- package/src/matrix/monitor/verification-events.ts +627 -0
- package/src/matrix/monitor/verification-utils.test.ts +47 -0
- package/src/matrix/monitor/verification-utils.ts +46 -0
- package/src/matrix/outbound-media-runtime.ts +1 -0
- package/src/matrix/poll-summary.ts +110 -0
- package/src/matrix/poll-types.test.ts +205 -0
- package/src/matrix/poll-types.ts +433 -0
- package/src/matrix/probe.runtime.ts +4 -0
- package/src/matrix/probe.test.ts +154 -0
- package/src/matrix/probe.ts +96 -0
- package/src/matrix/profile.test.ts +154 -0
- package/src/matrix/profile.ts +184 -0
- package/src/matrix/reaction-common.test.ts +96 -0
- package/src/matrix/reaction-common.ts +147 -0
- package/src/matrix/sdk/crypto-bootstrap.test.ts +505 -0
- package/src/matrix/sdk/crypto-bootstrap.ts +341 -0
- package/src/matrix/sdk/crypto-facade.test.ts +197 -0
- package/src/matrix/sdk/crypto-facade.ts +207 -0
- package/src/matrix/sdk/crypto-node.runtime.test.ts +27 -0
- package/src/matrix/sdk/crypto-node.runtime.ts +9 -0
- package/src/matrix/sdk/crypto-runtime.ts +11 -0
- package/src/matrix/sdk/decrypt-bridge.ts +356 -0
- package/src/matrix/sdk/event-helpers.test.ts +60 -0
- package/src/matrix/sdk/event-helpers.ts +71 -0
- package/src/matrix/sdk/http-client.test.ts +134 -0
- package/src/matrix/sdk/http-client.ts +87 -0
- package/src/matrix/sdk/idb-persistence-lock.ts +51 -0
- package/src/matrix/sdk/idb-persistence.lock-order.test.ts +108 -0
- package/src/matrix/sdk/idb-persistence.test-helpers.ts +88 -0
- package/src/matrix/sdk/idb-persistence.test.ts +149 -0
- package/src/matrix/sdk/idb-persistence.ts +283 -0
- package/src/matrix/sdk/logger.test.ts +25 -0
- package/src/matrix/sdk/logger.ts +108 -0
- package/src/matrix/sdk/read-response-with-limit.ts +19 -0
- package/src/matrix/sdk/recovery-key-store.test.ts +385 -0
- package/src/matrix/sdk/recovery-key-store.ts +430 -0
- package/src/matrix/sdk/transport.test.ts +161 -0
- package/src/matrix/sdk/transport.ts +344 -0
- package/src/matrix/sdk/types.ts +236 -0
- package/src/matrix/sdk/verification-manager.test.ts +509 -0
- package/src/matrix/sdk/verification-manager.ts +694 -0
- package/src/matrix/sdk/verification-status.ts +23 -0
- package/src/matrix/sdk.test.ts +2568 -0
- package/src/matrix/sdk.ts +1789 -0
- package/src/matrix/send/client.test.ts +174 -0
- package/src/matrix/send/client.ts +90 -0
- package/src/matrix/send/formatting.ts +189 -0
- package/src/matrix/send/media.ts +244 -0
- package/src/matrix/send/targets.test.ts +254 -0
- package/src/matrix/send/targets.ts +104 -0
- package/src/matrix/send/types.ts +134 -0
- package/src/matrix/send.test.ts +958 -0
- package/src/matrix/send.ts +609 -0
- package/src/matrix/session-store-metadata.ts +108 -0
- package/src/matrix/startup-abort.ts +44 -0
- package/src/matrix/sync-state.ts +27 -0
- package/src/matrix/target-ids.ts +102 -0
- package/src/matrix/thread-bindings-shared.ts +201 -0
- package/src/matrix/thread-bindings.test.ts +673 -0
- package/src/matrix/thread-bindings.ts +577 -0
- package/src/matrix-migration.runtime.ts +9 -0
- package/src/migration-config.test.ts +228 -0
- package/src/migration-config.ts +243 -0
- package/src/migration-snapshot-backup.ts +117 -0
- package/src/migration-snapshot.test.ts +184 -0
- package/src/migration-snapshot.ts +55 -0
- package/src/onboarding.resolve.test.ts +55 -0
- package/src/onboarding.test-harness.ts +158 -0
- package/src/onboarding.test.ts +665 -0
- package/src/onboarding.ts +773 -0
- package/src/outbound.test.ts +173 -0
- package/src/outbound.ts +78 -0
- package/src/plugin-entry.runtime.js +159 -0
- package/src/plugin-entry.runtime.test.ts +108 -0
- package/src/plugin-entry.runtime.ts +68 -0
- package/src/profile-update.ts +68 -0
- package/src/record-shared.ts +3 -0
- package/src/resolve-targets.test.ts +178 -0
- package/src/resolve-targets.ts +175 -0
- package/src/resolver.ts +21 -0
- package/src/runtime-api.ts +144 -0
- package/src/runtime.ts +7 -0
- package/src/secret-contract.ts +174 -0
- package/src/session-route.test.ts +315 -0
- package/src/session-route.ts +113 -0
- package/src/setup-bootstrap.ts +94 -0
- package/src/setup-config.ts +222 -0
- package/src/setup-contract.ts +89 -0
- package/src/setup-core.test.ts +326 -0
- package/src/setup-core.ts +50 -0
- package/src/setup-surface.ts +4 -0
- package/src/startup-maintenance.test.ts +227 -0
- package/src/startup-maintenance.ts +114 -0
- package/src/storage-paths.ts +92 -0
- package/src/test-helpers.ts +42 -0
- package/src/test-mocks.ts +55 -0
- package/src/test-runtime.ts +72 -0
- package/src/test-support/monitor-route-test-support.ts +8 -0
- package/src/tool-actions.runtime.ts +1 -0
- package/src/tool-actions.test.ts +422 -0
- package/src/tool-actions.ts +498 -0
- package/src/types.ts +230 -0
- package/test-api.ts +2 -0
- package/thread-bindings-runtime.ts +4 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
2
|
+
import {
|
|
3
|
+
type ChannelSetupDmPolicy,
|
|
4
|
+
type ChannelSetupWizardAdapter,
|
|
5
|
+
} from "openclaw/plugin-sdk/setup";
|
|
6
|
+
import { isPrivateNetworkOptInEnabled } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
7
|
+
import {
|
|
8
|
+
normalizeLowercaseStringOrEmpty,
|
|
9
|
+
normalizeOptionalString,
|
|
10
|
+
normalizeStringifiedOptionalString,
|
|
11
|
+
} from "openclaw/plugin-sdk/text-runtime";
|
|
12
|
+
import { requiresExplicitMatrixDefaultAccount } from "./account-selection.js";
|
|
13
|
+
import { listMatrixDirectoryGroupsLive } from "./directory-live.js";
|
|
14
|
+
import {
|
|
15
|
+
listMatrixAccountIds,
|
|
16
|
+
resolveDefaultMatrixAccountId,
|
|
17
|
+
resolveMatrixAccount,
|
|
18
|
+
resolveMatrixAccountConfig,
|
|
19
|
+
} from "./matrix/accounts.js";
|
|
20
|
+
import {
|
|
21
|
+
resolveValidatedMatrixHomeserverUrl,
|
|
22
|
+
validateMatrixHomeserverUrl,
|
|
23
|
+
} from "./matrix/client.js";
|
|
24
|
+
import { resolveMatrixEnvAuthReadiness } from "./matrix/client/env-auth.js";
|
|
25
|
+
import { resolveMatrixConfigFieldPath, updateMatrixAccountConfig } from "./matrix/config-update.js";
|
|
26
|
+
import { ensureMatrixSdkInstalled, isMatrixSdkAvailable } from "./matrix/deps.js";
|
|
27
|
+
import { resolveMatrixTargets } from "./resolve-targets.js";
|
|
28
|
+
import type { DmPolicy } from "./runtime-api.js";
|
|
29
|
+
import {
|
|
30
|
+
addWildcardAllowFrom,
|
|
31
|
+
formatDocsLink,
|
|
32
|
+
hasConfiguredSecretInput,
|
|
33
|
+
isPrivateOrLoopbackHost,
|
|
34
|
+
mergeAllowFromEntries,
|
|
35
|
+
normalizeAccountId,
|
|
36
|
+
promptAccountId,
|
|
37
|
+
promptChannelAccessConfig,
|
|
38
|
+
splitSetupEntries,
|
|
39
|
+
type RuntimeEnv,
|
|
40
|
+
type WizardPrompter,
|
|
41
|
+
} from "./runtime-api.js";
|
|
42
|
+
import { moveSingleMatrixAccountConfigToNamedAccount } from "./setup-config.js";
|
|
43
|
+
import type { CoreConfig, MatrixConfig } from "./types.js";
|
|
44
|
+
|
|
45
|
+
const channel = "matrix" as const;
|
|
46
|
+
type MatrixInviteAutoJoinPolicy = NonNullable<MatrixConfig["autoJoin"]>;
|
|
47
|
+
|
|
48
|
+
const matrixInviteAutoJoinOptions: Array<{
|
|
49
|
+
value: MatrixInviteAutoJoinPolicy;
|
|
50
|
+
label: string;
|
|
51
|
+
}> = [
|
|
52
|
+
{ value: "allowlist", label: "Allowlist (recommended)" },
|
|
53
|
+
{ value: "always", label: "Always (join every invite)" },
|
|
54
|
+
{ value: "off", label: "Off (do not auto-join invites)" },
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
function isMatrixInviteAutoJoinPolicy(value: string): value is MatrixInviteAutoJoinPolicy {
|
|
58
|
+
return value === "allowlist" || value === "always" || value === "off";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function isMatrixInviteAutoJoinTarget(entry: string): boolean {
|
|
62
|
+
return (
|
|
63
|
+
entry === "*" ||
|
|
64
|
+
(entry.startsWith("!") && entry.includes(":")) ||
|
|
65
|
+
(entry.startsWith("#") && entry.includes(":"))
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalizeMatrixInviteAutoJoinTargets(entries: string[]): string[] {
|
|
70
|
+
return [
|
|
71
|
+
...new Set(
|
|
72
|
+
entries
|
|
73
|
+
.map((entry) => normalizeOptionalString(entry))
|
|
74
|
+
.filter((entry): entry is string => Boolean(entry)),
|
|
75
|
+
),
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function resolveMatrixOnboardingAccountId(cfg: CoreConfig, accountId?: string): string {
|
|
80
|
+
return normalizeAccountId(
|
|
81
|
+
normalizeOptionalString(accountId) || resolveDefaultMatrixAccountId(cfg) || DEFAULT_ACCOUNT_ID,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function setMatrixDmPolicy(cfg: CoreConfig, policy: DmPolicy, accountId?: string) {
|
|
86
|
+
const resolvedAccountId = resolveMatrixOnboardingAccountId(cfg, accountId);
|
|
87
|
+
const existing = resolveMatrixAccountConfig({
|
|
88
|
+
cfg,
|
|
89
|
+
accountId: resolvedAccountId,
|
|
90
|
+
});
|
|
91
|
+
const allowFrom = policy === "open" ? addWildcardAllowFrom(existing.dm?.allowFrom) : undefined;
|
|
92
|
+
return updateMatrixAccountConfig(cfg, resolvedAccountId, {
|
|
93
|
+
dm: {
|
|
94
|
+
...existing.dm,
|
|
95
|
+
policy,
|
|
96
|
+
...(allowFrom ? { allowFrom } : {}),
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function noteMatrixAuthHelp(prompter: WizardPrompter): Promise<void> {
|
|
102
|
+
await prompter.note(
|
|
103
|
+
[
|
|
104
|
+
"Matrix requires a homeserver URL.",
|
|
105
|
+
"Use an access token (recommended) or password login to an existing account.",
|
|
106
|
+
"With access token: user ID is fetched automatically.",
|
|
107
|
+
"Env vars supported: LOBI_HOMESERVER, LOBI_USER_ID, LOBI_ACCESS_TOKEN, LOBI_PASSWORD, LOBI_DEVICE_ID, LOBI_DEVICE_NAME.",
|
|
108
|
+
"Per-account env vars: MATRIX_<ACCOUNT_ID>_HOMESERVER, MATRIX_<ACCOUNT_ID>_USER_ID, MATRIX_<ACCOUNT_ID>_ACCESS_TOKEN, MATRIX_<ACCOUNT_ID>_PASSWORD, MATRIX_<ACCOUNT_ID>_DEVICE_ID, MATRIX_<ACCOUNT_ID>_DEVICE_NAME.",
|
|
109
|
+
`Docs: ${formatDocsLink("/channels/matrix", "channels/matrix")}`,
|
|
110
|
+
].join("\n"),
|
|
111
|
+
"Matrix setup",
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function requiresMatrixPrivateNetworkOptIn(homeserver: string): boolean {
|
|
116
|
+
try {
|
|
117
|
+
const parsed = new URL(homeserver);
|
|
118
|
+
return parsed.protocol === "http:" && !isPrivateOrLoopbackHost(parsed.hostname);
|
|
119
|
+
} catch {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function promptMatrixAllowFrom(params: {
|
|
125
|
+
cfg: CoreConfig;
|
|
126
|
+
prompter: WizardPrompter;
|
|
127
|
+
accountId?: string;
|
|
128
|
+
}): Promise<CoreConfig> {
|
|
129
|
+
const { cfg, prompter } = params;
|
|
130
|
+
const accountId = resolveMatrixOnboardingAccountId(cfg, params.accountId);
|
|
131
|
+
const existingConfig = resolveMatrixAccountConfig({ cfg, accountId });
|
|
132
|
+
const existingAllowFrom = existingConfig.dm?.allowFrom ?? [];
|
|
133
|
+
const account = resolveMatrixAccount({ cfg, accountId });
|
|
134
|
+
const canResolve = account.configured;
|
|
135
|
+
|
|
136
|
+
const isFullUserId = (value: string) => value.startsWith("@") && value.includes(":");
|
|
137
|
+
|
|
138
|
+
while (true) {
|
|
139
|
+
const entry = await prompter.text({
|
|
140
|
+
message: "Matrix allowFrom (full @user:server; display name only if unique)",
|
|
141
|
+
placeholder: "@user:server",
|
|
142
|
+
initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,
|
|
143
|
+
validate: (value) => (normalizeOptionalString(value) ? undefined : "Required"),
|
|
144
|
+
});
|
|
145
|
+
const parts = splitSetupEntries(entry);
|
|
146
|
+
const resolvedIds: string[] = [];
|
|
147
|
+
const pending: string[] = [];
|
|
148
|
+
const unresolved: string[] = [];
|
|
149
|
+
const unresolvedNotes: string[] = [];
|
|
150
|
+
|
|
151
|
+
for (const part of parts) {
|
|
152
|
+
if (isFullUserId(part)) {
|
|
153
|
+
resolvedIds.push(part);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (!canResolve) {
|
|
157
|
+
unresolved.push(part);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
pending.push(part);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (pending.length > 0) {
|
|
164
|
+
const results = await resolveMatrixTargets({
|
|
165
|
+
cfg,
|
|
166
|
+
accountId,
|
|
167
|
+
inputs: pending,
|
|
168
|
+
kind: "user",
|
|
169
|
+
}).catch(() => []);
|
|
170
|
+
for (const result of results) {
|
|
171
|
+
if (result?.resolved && result.id) {
|
|
172
|
+
resolvedIds.push(result.id);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (result?.input) {
|
|
176
|
+
unresolved.push(result.input);
|
|
177
|
+
if (result.note) {
|
|
178
|
+
unresolvedNotes.push(`${result.input}: ${result.note}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (unresolved.length > 0) {
|
|
185
|
+
const details = unresolvedNotes.length > 0 ? unresolvedNotes : unresolved;
|
|
186
|
+
await prompter.note(
|
|
187
|
+
`Could not resolve:\n${details.join("\n")}\nUse full @user:server IDs.`,
|
|
188
|
+
"Matrix allowlist",
|
|
189
|
+
);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const unique = mergeAllowFromEntries(existingAllowFrom, resolvedIds);
|
|
194
|
+
return updateMatrixAccountConfig(cfg, accountId, {
|
|
195
|
+
dm: {
|
|
196
|
+
...existingConfig.dm,
|
|
197
|
+
policy: "allowlist",
|
|
198
|
+
allowFrom: unique,
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function setMatrixGroupPolicy(
|
|
205
|
+
cfg: CoreConfig,
|
|
206
|
+
groupPolicy: "open" | "allowlist" | "disabled",
|
|
207
|
+
accountId?: string,
|
|
208
|
+
) {
|
|
209
|
+
return updateMatrixAccountConfig(cfg, resolveMatrixOnboardingAccountId(cfg, accountId), {
|
|
210
|
+
groupPolicy,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function setMatrixGroupRooms(cfg: CoreConfig, roomKeys: string[], accountId?: string) {
|
|
215
|
+
const groups = Object.fromEntries(roomKeys.map((key) => [key, { enabled: true }]));
|
|
216
|
+
return updateMatrixAccountConfig(cfg, resolveMatrixOnboardingAccountId(cfg, accountId), {
|
|
217
|
+
groups,
|
|
218
|
+
rooms: null,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function setMatrixAutoJoin(
|
|
223
|
+
cfg: CoreConfig,
|
|
224
|
+
autoJoin: MatrixInviteAutoJoinPolicy,
|
|
225
|
+
autoJoinAllowlist: string[],
|
|
226
|
+
accountId?: string,
|
|
227
|
+
) {
|
|
228
|
+
return updateMatrixAccountConfig(cfg, resolveMatrixOnboardingAccountId(cfg, accountId), {
|
|
229
|
+
autoJoin,
|
|
230
|
+
autoJoinAllowlist: autoJoin === "allowlist" ? autoJoinAllowlist : null,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function configureMatrixInviteAutoJoin(params: {
|
|
235
|
+
cfg: CoreConfig;
|
|
236
|
+
prompter: WizardPrompter;
|
|
237
|
+
accountId?: string;
|
|
238
|
+
}): Promise<CoreConfig> {
|
|
239
|
+
const accountId = resolveMatrixOnboardingAccountId(params.cfg, params.accountId);
|
|
240
|
+
const existingConfig = resolveMatrixAccountConfig({ cfg: params.cfg, accountId });
|
|
241
|
+
const currentPolicy = existingConfig.autoJoin ?? "off";
|
|
242
|
+
const currentAllowlist = (existingConfig.autoJoinAllowlist ?? []).map((entry) => String(entry));
|
|
243
|
+
const hasExistingConfig = existingConfig.autoJoin !== undefined || currentAllowlist.length > 0;
|
|
244
|
+
|
|
245
|
+
await params.prompter.note(
|
|
246
|
+
[
|
|
247
|
+
"WARNING: Matrix invite auto-join defaults to off.",
|
|
248
|
+
"OpenClaw agents will not join invited rooms or fresh DM-style invites unless you set autoJoin.",
|
|
249
|
+
'Choose "allowlist" to restrict joins or "always" to join every invite.',
|
|
250
|
+
].join("\n"),
|
|
251
|
+
"Matrix invite auto-join",
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const wants = await params.prompter.confirm({
|
|
255
|
+
message: hasExistingConfig
|
|
256
|
+
? "Update Matrix invite auto-join?"
|
|
257
|
+
: "Configure Matrix invite auto-join?",
|
|
258
|
+
initialValue: hasExistingConfig ? currentPolicy !== "off" : true,
|
|
259
|
+
});
|
|
260
|
+
if (!wants) {
|
|
261
|
+
return params.cfg;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const selectedPolicy = await params.prompter.select({
|
|
265
|
+
message: "Matrix invite auto-join",
|
|
266
|
+
options: matrixInviteAutoJoinOptions,
|
|
267
|
+
initialValue: currentPolicy,
|
|
268
|
+
});
|
|
269
|
+
if (!isMatrixInviteAutoJoinPolicy(selectedPolicy)) {
|
|
270
|
+
throw new Error(`Unsupported Matrix invite auto-join policy: ${String(selectedPolicy)}`);
|
|
271
|
+
}
|
|
272
|
+
const policy = selectedPolicy;
|
|
273
|
+
|
|
274
|
+
if (policy === "off") {
|
|
275
|
+
await params.prompter.note(
|
|
276
|
+
[
|
|
277
|
+
"Matrix invite auto-join remains off.",
|
|
278
|
+
"Agents will not join invited rooms or fresh DM-style invites until you change autoJoin.",
|
|
279
|
+
].join("\n"),
|
|
280
|
+
"Matrix invite auto-join",
|
|
281
|
+
);
|
|
282
|
+
return setMatrixAutoJoin(params.cfg, policy, [], accountId);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (policy === "always") {
|
|
286
|
+
return setMatrixAutoJoin(params.cfg, policy, [], accountId);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
while (true) {
|
|
290
|
+
const rawAllowlist = await params.prompter.text({
|
|
291
|
+
message: "Matrix invite auto-join allowlist (comma-separated)",
|
|
292
|
+
placeholder: "!roomId:server, #alias:server, *",
|
|
293
|
+
initialValue: currentAllowlist[0] ? currentAllowlist.join(", ") : undefined,
|
|
294
|
+
validate: (value) => {
|
|
295
|
+
const entries = splitSetupEntries(value);
|
|
296
|
+
return entries.length > 0 ? undefined : "Required";
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
const allowlist = normalizeMatrixInviteAutoJoinTargets(splitSetupEntries(rawAllowlist));
|
|
300
|
+
const invalidEntries = allowlist.filter((entry) => !isMatrixInviteAutoJoinTarget(entry));
|
|
301
|
+
if (allowlist.length === 0 || invalidEntries.length > 0) {
|
|
302
|
+
await params.prompter.note(
|
|
303
|
+
[
|
|
304
|
+
"Use only stable Matrix invite targets for auto-join: !roomId:server, #alias:server, or *.",
|
|
305
|
+
invalidEntries.length > 0 ? `Invalid: ${invalidEntries.join(", ")}` : undefined,
|
|
306
|
+
]
|
|
307
|
+
.filter(Boolean)
|
|
308
|
+
.join("\n"),
|
|
309
|
+
"Matrix invite auto-join",
|
|
310
|
+
);
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
return setMatrixAutoJoin(params.cfg, "allowlist", allowlist, accountId);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async function configureMatrixAccessPrompts(params: {
|
|
318
|
+
cfg: CoreConfig;
|
|
319
|
+
prompter: WizardPrompter;
|
|
320
|
+
forceAllowFrom: boolean;
|
|
321
|
+
accountId: string;
|
|
322
|
+
}): Promise<CoreConfig> {
|
|
323
|
+
let next = params.cfg;
|
|
324
|
+
|
|
325
|
+
if (params.forceAllowFrom) {
|
|
326
|
+
next = await promptMatrixAllowFrom({
|
|
327
|
+
cfg: next,
|
|
328
|
+
prompter: params.prompter,
|
|
329
|
+
accountId: params.accountId,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const existingAccountConfig = resolveMatrixAccountConfig({
|
|
334
|
+
cfg: next,
|
|
335
|
+
accountId: params.accountId,
|
|
336
|
+
});
|
|
337
|
+
const existingGroups = existingAccountConfig.groups ?? existingAccountConfig.rooms;
|
|
338
|
+
const accessConfig = await promptChannelAccessConfig({
|
|
339
|
+
prompter: params.prompter,
|
|
340
|
+
label: "Matrix rooms",
|
|
341
|
+
currentPolicy: existingAccountConfig.groupPolicy ?? "allowlist",
|
|
342
|
+
currentEntries: Object.keys(existingGroups ?? {}),
|
|
343
|
+
placeholder: "!roomId:server, #alias:server, Project Room",
|
|
344
|
+
updatePrompt: Boolean(existingGroups),
|
|
345
|
+
});
|
|
346
|
+
if (accessConfig) {
|
|
347
|
+
if (accessConfig.policy !== "allowlist") {
|
|
348
|
+
next = setMatrixGroupPolicy(next, accessConfig.policy, params.accountId);
|
|
349
|
+
} else {
|
|
350
|
+
let roomKeys = accessConfig.entries;
|
|
351
|
+
if (accessConfig.entries.length > 0) {
|
|
352
|
+
try {
|
|
353
|
+
const resolvedIds: string[] = [];
|
|
354
|
+
const unresolved: string[] = [];
|
|
355
|
+
for (const entry of accessConfig.entries) {
|
|
356
|
+
const trimmed = normalizeOptionalString(entry) ?? "";
|
|
357
|
+
if (!trimmed) {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
const cleaned = trimmed.replace(/^(room|channel):/i, "").trim();
|
|
361
|
+
if (cleaned.startsWith("!") && cleaned.includes(":")) {
|
|
362
|
+
resolvedIds.push(cleaned);
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
const matches = await listMatrixDirectoryGroupsLive({
|
|
366
|
+
cfg: next,
|
|
367
|
+
accountId: params.accountId,
|
|
368
|
+
query: trimmed,
|
|
369
|
+
limit: 10,
|
|
370
|
+
});
|
|
371
|
+
const exact = matches.find(
|
|
372
|
+
(match) =>
|
|
373
|
+
normalizeLowercaseStringOrEmpty(match.name) ===
|
|
374
|
+
normalizeLowercaseStringOrEmpty(trimmed),
|
|
375
|
+
);
|
|
376
|
+
const best = exact ?? matches[0];
|
|
377
|
+
if (best?.id) {
|
|
378
|
+
resolvedIds.push(best.id);
|
|
379
|
+
} else {
|
|
380
|
+
unresolved.push(entry);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
roomKeys = [
|
|
384
|
+
...resolvedIds,
|
|
385
|
+
...unresolved
|
|
386
|
+
.map((entry) => normalizeOptionalString(entry))
|
|
387
|
+
.filter((entry): entry is string => Boolean(entry)),
|
|
388
|
+
];
|
|
389
|
+
if (resolvedIds.length > 0 || unresolved.length > 0) {
|
|
390
|
+
await params.prompter.note(
|
|
391
|
+
[
|
|
392
|
+
resolvedIds.length > 0 ? `Resolved: ${resolvedIds.join(", ")}` : undefined,
|
|
393
|
+
unresolved.length > 0
|
|
394
|
+
? `Unresolved (kept as typed): ${unresolved.join(", ")}`
|
|
395
|
+
: undefined,
|
|
396
|
+
]
|
|
397
|
+
.filter(Boolean)
|
|
398
|
+
.join("\n"),
|
|
399
|
+
"Matrix rooms",
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
} catch (err) {
|
|
403
|
+
await params.prompter.note(
|
|
404
|
+
`Room lookup failed; keeping entries as typed. ${String(err)}`,
|
|
405
|
+
"Matrix rooms",
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
next = setMatrixGroupPolicy(next, "allowlist", params.accountId);
|
|
410
|
+
next = setMatrixGroupRooms(next, roomKeys, params.accountId);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
return await configureMatrixInviteAutoJoin({
|
|
415
|
+
cfg: next,
|
|
416
|
+
prompter: params.prompter,
|
|
417
|
+
accountId: params.accountId,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const dmPolicy: ChannelSetupDmPolicy = {
|
|
422
|
+
label: "Matrix",
|
|
423
|
+
channel,
|
|
424
|
+
policyKey: "channels.lobi.dm.policy",
|
|
425
|
+
allowFromKey: "channels.lobi.dm.allowFrom",
|
|
426
|
+
resolveConfigKeys: (cfg, accountId) => {
|
|
427
|
+
const effectiveAccountId = resolveMatrixOnboardingAccountId(cfg as CoreConfig, accountId);
|
|
428
|
+
return {
|
|
429
|
+
policyKey: resolveMatrixConfigFieldPath(cfg as CoreConfig, effectiveAccountId, "dm.policy"),
|
|
430
|
+
allowFromKey: resolveMatrixConfigFieldPath(
|
|
431
|
+
cfg as CoreConfig,
|
|
432
|
+
effectiveAccountId,
|
|
433
|
+
"dm.allowFrom",
|
|
434
|
+
),
|
|
435
|
+
};
|
|
436
|
+
},
|
|
437
|
+
getCurrent: (cfg, accountId) =>
|
|
438
|
+
resolveMatrixAccountConfig({
|
|
439
|
+
cfg: cfg as CoreConfig,
|
|
440
|
+
accountId: resolveMatrixOnboardingAccountId(cfg as CoreConfig, accountId),
|
|
441
|
+
}).dm?.policy ?? "pairing",
|
|
442
|
+
setPolicy: (cfg, policy, accountId) => setMatrixDmPolicy(cfg as CoreConfig, policy, accountId),
|
|
443
|
+
promptAllowFrom: promptMatrixAllowFrom,
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
type MatrixConfigureIntent = "update" | "add-account";
|
|
447
|
+
|
|
448
|
+
async function runMatrixConfigure(params: {
|
|
449
|
+
cfg: CoreConfig;
|
|
450
|
+
runtime: RuntimeEnv;
|
|
451
|
+
prompter: WizardPrompter;
|
|
452
|
+
forceAllowFrom: boolean;
|
|
453
|
+
accountOverrides?: Partial<Record<string, string>>;
|
|
454
|
+
shouldPromptAccountIds?: boolean;
|
|
455
|
+
intent: MatrixConfigureIntent;
|
|
456
|
+
}): Promise<{ cfg: CoreConfig; accountId: string }> {
|
|
457
|
+
let next = params.cfg;
|
|
458
|
+
await ensureMatrixSdkInstalled({
|
|
459
|
+
runtime: params.runtime,
|
|
460
|
+
confirm: async (message) =>
|
|
461
|
+
await params.prompter.confirm({
|
|
462
|
+
message,
|
|
463
|
+
initialValue: true,
|
|
464
|
+
}),
|
|
465
|
+
});
|
|
466
|
+
const defaultAccountId = resolveDefaultMatrixAccountId(next);
|
|
467
|
+
let accountId = defaultAccountId || DEFAULT_ACCOUNT_ID;
|
|
468
|
+
if (params.intent === "add-account") {
|
|
469
|
+
const enteredName =
|
|
470
|
+
normalizeStringifiedOptionalString(
|
|
471
|
+
await params.prompter.text({
|
|
472
|
+
message: "Matrix account name",
|
|
473
|
+
validate: (value) => (normalizeOptionalString(value) ? undefined : "Required"),
|
|
474
|
+
}),
|
|
475
|
+
) ?? "";
|
|
476
|
+
accountId = normalizeAccountId(enteredName);
|
|
477
|
+
if (enteredName !== accountId) {
|
|
478
|
+
await params.prompter.note(`Account id will be "${accountId}".`, "Matrix account");
|
|
479
|
+
}
|
|
480
|
+
if (accountId !== DEFAULT_ACCOUNT_ID) {
|
|
481
|
+
next = moveSingleMatrixAccountConfigToNamedAccount(next);
|
|
482
|
+
}
|
|
483
|
+
next = updateMatrixAccountConfig(next, accountId, { name: enteredName, enabled: true });
|
|
484
|
+
} else {
|
|
485
|
+
const override = normalizeOptionalString(params.accountOverrides?.[channel]);
|
|
486
|
+
if (override) {
|
|
487
|
+
accountId = normalizeAccountId(override);
|
|
488
|
+
} else if (params.shouldPromptAccountIds) {
|
|
489
|
+
accountId = await promptAccountId({
|
|
490
|
+
cfg: next,
|
|
491
|
+
prompter: params.prompter,
|
|
492
|
+
label: "Matrix",
|
|
493
|
+
currentId: accountId,
|
|
494
|
+
listAccountIds: (inputCfg) => listMatrixAccountIds(inputCfg as CoreConfig),
|
|
495
|
+
defaultAccountId,
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const existing = resolveMatrixAccountConfig({ cfg: next, accountId });
|
|
501
|
+
const account = resolveMatrixAccount({ cfg: next, accountId });
|
|
502
|
+
if (!account.configured) {
|
|
503
|
+
await noteMatrixAuthHelp(params.prompter);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const envReadiness = resolveMatrixEnvAuthReadiness(accountId, process.env);
|
|
507
|
+
const envReady = envReadiness.ready;
|
|
508
|
+
const envHomeserver = envReadiness.homeserver;
|
|
509
|
+
const envUserId = envReadiness.userId;
|
|
510
|
+
|
|
511
|
+
if (
|
|
512
|
+
envReady &&
|
|
513
|
+
!existing.homeserver &&
|
|
514
|
+
!existing.userId &&
|
|
515
|
+
!existing.accessToken &&
|
|
516
|
+
!existing.password
|
|
517
|
+
) {
|
|
518
|
+
const useEnv = await params.prompter.confirm({
|
|
519
|
+
message: `Matrix env vars detected (${envReadiness.sourceHint}). Use env values?`,
|
|
520
|
+
initialValue: true,
|
|
521
|
+
});
|
|
522
|
+
if (useEnv) {
|
|
523
|
+
next = updateMatrixAccountConfig(next, accountId, { enabled: true });
|
|
524
|
+
next = await configureMatrixAccessPrompts({
|
|
525
|
+
cfg: next,
|
|
526
|
+
prompter: params.prompter,
|
|
527
|
+
forceAllowFrom: params.forceAllowFrom,
|
|
528
|
+
accountId,
|
|
529
|
+
});
|
|
530
|
+
return { cfg: next, accountId };
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const homeserver =
|
|
535
|
+
normalizeStringifiedOptionalString(
|
|
536
|
+
await params.prompter.text({
|
|
537
|
+
message: "Matrix homeserver URL",
|
|
538
|
+
initialValue: existing.homeserver ?? envHomeserver,
|
|
539
|
+
validate: (value) => {
|
|
540
|
+
try {
|
|
541
|
+
validateMatrixHomeserverUrl(value, {
|
|
542
|
+
allowPrivateNetwork: true,
|
|
543
|
+
});
|
|
544
|
+
return undefined;
|
|
545
|
+
} catch (error) {
|
|
546
|
+
return error instanceof Error ? error.message : "Invalid Matrix homeserver URL";
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
}),
|
|
550
|
+
) ?? "";
|
|
551
|
+
const requiresAllowPrivateNetwork = requiresMatrixPrivateNetworkOptIn(homeserver);
|
|
552
|
+
const shouldPromptAllowPrivateNetwork =
|
|
553
|
+
requiresAllowPrivateNetwork || isPrivateNetworkOptInEnabled(existing);
|
|
554
|
+
const allowPrivateNetwork = shouldPromptAllowPrivateNetwork
|
|
555
|
+
? await params.prompter.confirm({
|
|
556
|
+
message: "Allow private/internal Matrix homeserver traffic for this account?",
|
|
557
|
+
initialValue: isPrivateNetworkOptInEnabled(existing) || requiresAllowPrivateNetwork,
|
|
558
|
+
})
|
|
559
|
+
: false;
|
|
560
|
+
if (requiresAllowPrivateNetwork && !allowPrivateNetwork) {
|
|
561
|
+
throw new Error("Matrix homeserver requires explicit private-network opt-in");
|
|
562
|
+
}
|
|
563
|
+
await resolveValidatedMatrixHomeserverUrl(homeserver, {
|
|
564
|
+
dangerouslyAllowPrivateNetwork: allowPrivateNetwork,
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
let accessToken = existing.accessToken;
|
|
568
|
+
let password = existing.password;
|
|
569
|
+
let userId = existing.userId ?? "";
|
|
570
|
+
|
|
571
|
+
if (hasConfiguredSecretInput(accessToken) || hasConfiguredSecretInput(password)) {
|
|
572
|
+
const keep = await params.prompter.confirm({
|
|
573
|
+
message: "Matrix credentials already configured. Keep them?",
|
|
574
|
+
initialValue: true,
|
|
575
|
+
});
|
|
576
|
+
if (!keep) {
|
|
577
|
+
accessToken = undefined;
|
|
578
|
+
password = undefined;
|
|
579
|
+
userId = "";
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if (!hasConfiguredSecretInput(accessToken) && !hasConfiguredSecretInput(password)) {
|
|
584
|
+
const authMode = await params.prompter.select({
|
|
585
|
+
message: "Matrix auth method",
|
|
586
|
+
options: [
|
|
587
|
+
{ value: "token", label: "Access token (user ID fetched automatically)" },
|
|
588
|
+
{ value: "password", label: "Password (requires user ID)" },
|
|
589
|
+
],
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
if (authMode === "token") {
|
|
593
|
+
accessToken =
|
|
594
|
+
normalizeStringifiedOptionalString(
|
|
595
|
+
await params.prompter.text({
|
|
596
|
+
message: "Matrix access token",
|
|
597
|
+
validate: (value) => (normalizeOptionalString(value) ? undefined : "Required"),
|
|
598
|
+
}),
|
|
599
|
+
) ?? "";
|
|
600
|
+
password = undefined;
|
|
601
|
+
userId = "";
|
|
602
|
+
} else {
|
|
603
|
+
userId =
|
|
604
|
+
normalizeStringifiedOptionalString(
|
|
605
|
+
await params.prompter.text({
|
|
606
|
+
message: "Matrix user ID",
|
|
607
|
+
initialValue: existing.userId ?? envUserId,
|
|
608
|
+
validate: (value) => {
|
|
609
|
+
const raw = normalizeOptionalString(value) ?? "";
|
|
610
|
+
if (!raw) {
|
|
611
|
+
return "Required";
|
|
612
|
+
}
|
|
613
|
+
if (!raw.startsWith("@")) {
|
|
614
|
+
return "Matrix user IDs should start with @";
|
|
615
|
+
}
|
|
616
|
+
if (!raw.includes(":")) {
|
|
617
|
+
return "Matrix user IDs should include a server (:server)";
|
|
618
|
+
}
|
|
619
|
+
return undefined;
|
|
620
|
+
},
|
|
621
|
+
}),
|
|
622
|
+
) ?? "";
|
|
623
|
+
password =
|
|
624
|
+
normalizeStringifiedOptionalString(
|
|
625
|
+
await params.prompter.text({
|
|
626
|
+
message: "Matrix password",
|
|
627
|
+
validate: (value) => (normalizeOptionalString(value) ? undefined : "Required"),
|
|
628
|
+
}),
|
|
629
|
+
) ?? "";
|
|
630
|
+
accessToken = undefined;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const deviceName =
|
|
635
|
+
normalizeStringifiedOptionalString(
|
|
636
|
+
await params.prompter.text({
|
|
637
|
+
message: "Matrix device name (optional)",
|
|
638
|
+
initialValue: existing.deviceName ?? "OpenClaw Gateway",
|
|
639
|
+
}),
|
|
640
|
+
) ?? "";
|
|
641
|
+
|
|
642
|
+
const enableEncryption = await params.prompter.confirm({
|
|
643
|
+
message: "Enable end-to-end encryption (E2EE)?",
|
|
644
|
+
initialValue: existing.encryption ?? false,
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
next = updateMatrixAccountConfig(next, accountId, {
|
|
648
|
+
enabled: true,
|
|
649
|
+
homeserver,
|
|
650
|
+
...(shouldPromptAllowPrivateNetwork
|
|
651
|
+
? { allowPrivateNetwork: allowPrivateNetwork ? true : null }
|
|
652
|
+
: {}),
|
|
653
|
+
userId: userId || null,
|
|
654
|
+
accessToken: accessToken ?? null,
|
|
655
|
+
password: password ?? null,
|
|
656
|
+
deviceName: deviceName || null,
|
|
657
|
+
encryption: enableEncryption,
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
next = await configureMatrixAccessPrompts({
|
|
661
|
+
cfg: next,
|
|
662
|
+
prompter: params.prompter,
|
|
663
|
+
forceAllowFrom: params.forceAllowFrom,
|
|
664
|
+
accountId,
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
return { cfg: next, accountId };
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
export const matrixOnboardingAdapter: ChannelSetupWizardAdapter = {
|
|
671
|
+
channel,
|
|
672
|
+
getStatus: async ({ cfg, accountOverrides }) => {
|
|
673
|
+
const resolvedCfg = cfg as CoreConfig;
|
|
674
|
+
const sdkReady = isMatrixSdkAvailable();
|
|
675
|
+
if (!accountOverrides[channel] && requiresExplicitMatrixDefaultAccount(resolvedCfg)) {
|
|
676
|
+
return {
|
|
677
|
+
channel,
|
|
678
|
+
configured: false,
|
|
679
|
+
statusLines: ['Matrix: set "channels.lobi.defaultAccount" to select a named account'],
|
|
680
|
+
selectionHint: !sdkReady ? "install Matrix deps" : "set defaultAccount",
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
const account = resolveMatrixAccount({
|
|
684
|
+
cfg: resolvedCfg,
|
|
685
|
+
accountId: resolveMatrixOnboardingAccountId(resolvedCfg, accountOverrides[channel]),
|
|
686
|
+
});
|
|
687
|
+
const configured = account.configured;
|
|
688
|
+
return {
|
|
689
|
+
channel,
|
|
690
|
+
configured,
|
|
691
|
+
statusLines: [
|
|
692
|
+
`Matrix: ${configured ? "configured" : "needs homeserver + access token or password"}`,
|
|
693
|
+
],
|
|
694
|
+
selectionHint: !sdkReady ? "install Matrix deps" : configured ? "configured" : "needs auth",
|
|
695
|
+
};
|
|
696
|
+
},
|
|
697
|
+
configure: async ({
|
|
698
|
+
cfg,
|
|
699
|
+
runtime,
|
|
700
|
+
prompter,
|
|
701
|
+
forceAllowFrom,
|
|
702
|
+
accountOverrides,
|
|
703
|
+
shouldPromptAccountIds,
|
|
704
|
+
}) =>
|
|
705
|
+
await runMatrixConfigure({
|
|
706
|
+
cfg: cfg as CoreConfig,
|
|
707
|
+
runtime,
|
|
708
|
+
prompter,
|
|
709
|
+
forceAllowFrom,
|
|
710
|
+
accountOverrides,
|
|
711
|
+
shouldPromptAccountIds,
|
|
712
|
+
intent: "update",
|
|
713
|
+
}),
|
|
714
|
+
configureInteractive: async ({
|
|
715
|
+
cfg,
|
|
716
|
+
runtime,
|
|
717
|
+
prompter,
|
|
718
|
+
forceAllowFrom,
|
|
719
|
+
accountOverrides,
|
|
720
|
+
shouldPromptAccountIds,
|
|
721
|
+
configured,
|
|
722
|
+
}) => {
|
|
723
|
+
if (!configured) {
|
|
724
|
+
return await runMatrixConfigure({
|
|
725
|
+
cfg: cfg as CoreConfig,
|
|
726
|
+
runtime,
|
|
727
|
+
prompter,
|
|
728
|
+
forceAllowFrom,
|
|
729
|
+
accountOverrides,
|
|
730
|
+
shouldPromptAccountIds,
|
|
731
|
+
intent: "update",
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
const action = await prompter.select({
|
|
735
|
+
message: "Matrix already configured. What do you want to do?",
|
|
736
|
+
options: [
|
|
737
|
+
{ value: "update", label: "Modify settings" },
|
|
738
|
+
{ value: "add-account", label: "Add account" },
|
|
739
|
+
{ value: "skip", label: "Skip (leave as-is)" },
|
|
740
|
+
],
|
|
741
|
+
initialValue: "update",
|
|
742
|
+
});
|
|
743
|
+
if (action === "skip") {
|
|
744
|
+
return "skip";
|
|
745
|
+
}
|
|
746
|
+
return await runMatrixConfigure({
|
|
747
|
+
cfg: cfg as CoreConfig,
|
|
748
|
+
runtime,
|
|
749
|
+
prompter,
|
|
750
|
+
forceAllowFrom,
|
|
751
|
+
accountOverrides,
|
|
752
|
+
shouldPromptAccountIds,
|
|
753
|
+
intent: action === "add-account" ? "add-account" : "update",
|
|
754
|
+
});
|
|
755
|
+
},
|
|
756
|
+
afterConfigWritten: async ({ previousCfg, cfg, accountId, runtime }) => {
|
|
757
|
+
const { runMatrixSetupBootstrapAfterConfigWrite } = await import("./setup-bootstrap.js");
|
|
758
|
+
await runMatrixSetupBootstrapAfterConfigWrite({
|
|
759
|
+
previousCfg: previousCfg as CoreConfig,
|
|
760
|
+
cfg: cfg as CoreConfig,
|
|
761
|
+
accountId,
|
|
762
|
+
runtime,
|
|
763
|
+
});
|
|
764
|
+
},
|
|
765
|
+
dmPolicy,
|
|
766
|
+
disable: (cfg) => ({
|
|
767
|
+
...(cfg as CoreConfig),
|
|
768
|
+
channels: {
|
|
769
|
+
...(cfg as CoreConfig).channels,
|
|
770
|
+
matrix: { ...(cfg as CoreConfig).channels?.["matrix"], enabled: false },
|
|
771
|
+
},
|
|
772
|
+
}),
|
|
773
|
+
};
|