@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,194 @@
|
|
|
1
|
+
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
2
|
+
import { hasConfiguredSecretInput } from "openclaw/plugin-sdk/secret-input";
|
|
3
|
+
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
|
4
|
+
import {
|
|
5
|
+
resolveConfiguredMatrixAccountIds,
|
|
6
|
+
resolveMatrixDefaultOrOnlyAccountId,
|
|
7
|
+
} from "../account-selection.js";
|
|
8
|
+
import { resolveMatrixAccountStringValues } from "../auth-precedence.js";
|
|
9
|
+
import type { CoreConfig, MatrixConfig } from "../types.js";
|
|
10
|
+
import {
|
|
11
|
+
findMatrixAccountConfig,
|
|
12
|
+
resolveMatrixAccountConfig,
|
|
13
|
+
resolveMatrixBaseConfig,
|
|
14
|
+
} from "./account-config.js";
|
|
15
|
+
import { resolveGlobalMatrixEnvConfig, resolveScopedMatrixEnvConfig } from "./client/env-auth.js";
|
|
16
|
+
import { credentialsMatchConfig, loadMatrixCredentials } from "./credentials-read.js";
|
|
17
|
+
|
|
18
|
+
export type ResolvedMatrixAccount = {
|
|
19
|
+
accountId: string;
|
|
20
|
+
enabled: boolean;
|
|
21
|
+
name?: string;
|
|
22
|
+
configured: boolean;
|
|
23
|
+
homeserver?: string;
|
|
24
|
+
userId?: string;
|
|
25
|
+
config: MatrixConfig;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
function clean(value: unknown): string {
|
|
29
|
+
return normalizeOptionalString(value) ?? "";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function resolveMatrixAccountAuthView(params: {
|
|
33
|
+
cfg: CoreConfig;
|
|
34
|
+
accountId: string;
|
|
35
|
+
env: NodeJS.ProcessEnv;
|
|
36
|
+
}): {
|
|
37
|
+
homeserver: string;
|
|
38
|
+
userId: string;
|
|
39
|
+
accessToken?: string;
|
|
40
|
+
password?: string;
|
|
41
|
+
} {
|
|
42
|
+
const normalizedAccountId = normalizeAccountId(params.accountId);
|
|
43
|
+
const matrix = resolveMatrixBaseConfig(params.cfg);
|
|
44
|
+
const account = findMatrixAccountConfig(params.cfg, normalizedAccountId) ?? {};
|
|
45
|
+
const resolvedStrings = resolveMatrixAccountStringValues({
|
|
46
|
+
accountId: normalizedAccountId,
|
|
47
|
+
account: {
|
|
48
|
+
homeserver: clean(account.homeserver),
|
|
49
|
+
userId: clean(account.userId),
|
|
50
|
+
accessToken: typeof account.accessToken === "string" ? clean(account.accessToken) : "",
|
|
51
|
+
password: typeof account.password === "string" ? clean(account.password) : "",
|
|
52
|
+
deviceId: clean(account.deviceId),
|
|
53
|
+
deviceName: clean(account.deviceName),
|
|
54
|
+
},
|
|
55
|
+
scopedEnv: resolveScopedMatrixEnvConfig(normalizedAccountId, params.env),
|
|
56
|
+
channel: {
|
|
57
|
+
homeserver: clean(matrix.homeserver),
|
|
58
|
+
userId: clean(matrix.userId),
|
|
59
|
+
accessToken: typeof matrix.accessToken === "string" ? clean(matrix.accessToken) : "",
|
|
60
|
+
password: typeof matrix.password === "string" ? clean(matrix.password) : "",
|
|
61
|
+
deviceId: clean(matrix.deviceId),
|
|
62
|
+
deviceName: clean(matrix.deviceName),
|
|
63
|
+
},
|
|
64
|
+
globalEnv: resolveGlobalMatrixEnvConfig(params.env),
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
homeserver: resolvedStrings.homeserver,
|
|
68
|
+
userId: resolvedStrings.userId,
|
|
69
|
+
accessToken: resolvedStrings.accessToken || undefined,
|
|
70
|
+
password: resolvedStrings.password || undefined,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function resolveMatrixAccountUserId(params: {
|
|
75
|
+
cfg: CoreConfig;
|
|
76
|
+
accountId: string;
|
|
77
|
+
env?: NodeJS.ProcessEnv;
|
|
78
|
+
}): string | null {
|
|
79
|
+
const env = params.env ?? process.env;
|
|
80
|
+
const authView = resolveMatrixAccountAuthView({
|
|
81
|
+
cfg: params.cfg,
|
|
82
|
+
accountId: params.accountId,
|
|
83
|
+
env,
|
|
84
|
+
});
|
|
85
|
+
const configuredUserId = authView.userId.trim();
|
|
86
|
+
if (configuredUserId) {
|
|
87
|
+
return configuredUserId;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const stored = loadMatrixCredentials(env, params.accountId);
|
|
91
|
+
if (!stored) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
if (authView.homeserver && stored.homeserver !== authView.homeserver) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
if (authView.accessToken && stored.accessToken !== authView.accessToken) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return stored.userId.trim() || null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function listMatrixAccountIds(cfg: CoreConfig): string[] {
|
|
104
|
+
const ids = resolveConfiguredMatrixAccountIds(cfg, process.env);
|
|
105
|
+
return ids.length > 0 ? ids : [DEFAULT_ACCOUNT_ID];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function resolveDefaultMatrixAccountId(cfg: CoreConfig): string {
|
|
109
|
+
return normalizeAccountId(resolveMatrixDefaultOrOnlyAccountId(cfg));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function resolveConfiguredMatrixBotUserIds(params: {
|
|
113
|
+
cfg: CoreConfig;
|
|
114
|
+
accountId?: string | null;
|
|
115
|
+
env?: NodeJS.ProcessEnv;
|
|
116
|
+
}): Set<string> {
|
|
117
|
+
const env = params.env ?? process.env;
|
|
118
|
+
const currentAccountId = normalizeAccountId(params.accountId);
|
|
119
|
+
const accountIds = new Set(resolveConfiguredMatrixAccountIds(params.cfg, env));
|
|
120
|
+
if (resolveMatrixAccount({ cfg: params.cfg, accountId: DEFAULT_ACCOUNT_ID, env }).configured) {
|
|
121
|
+
accountIds.add(DEFAULT_ACCOUNT_ID);
|
|
122
|
+
}
|
|
123
|
+
const ids = new Set<string>();
|
|
124
|
+
|
|
125
|
+
for (const accountId of accountIds) {
|
|
126
|
+
if (normalizeAccountId(accountId) === currentAccountId) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (!resolveMatrixAccount({ cfg: params.cfg, accountId, env }).configured) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const userId = resolveMatrixAccountUserId({
|
|
133
|
+
cfg: params.cfg,
|
|
134
|
+
accountId,
|
|
135
|
+
env,
|
|
136
|
+
});
|
|
137
|
+
if (userId) {
|
|
138
|
+
ids.add(userId);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return ids;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function resolveMatrixAccount(params: {
|
|
146
|
+
cfg: CoreConfig;
|
|
147
|
+
accountId?: string | null;
|
|
148
|
+
env?: NodeJS.ProcessEnv;
|
|
149
|
+
}): ResolvedMatrixAccount {
|
|
150
|
+
const env = params.env ?? process.env;
|
|
151
|
+
const accountId = normalizeAccountId(
|
|
152
|
+
params.accountId ?? resolveDefaultMatrixAccountId(params.cfg),
|
|
153
|
+
);
|
|
154
|
+
const matrixBase = resolveMatrixBaseConfig(params.cfg);
|
|
155
|
+
const base = resolveMatrixAccountConfig({ cfg: params.cfg, accountId, env });
|
|
156
|
+
const explicitAuthConfig =
|
|
157
|
+
accountId === DEFAULT_ACCOUNT_ID
|
|
158
|
+
? base
|
|
159
|
+
: (findMatrixAccountConfig(params.cfg, accountId) ?? {});
|
|
160
|
+
const enabled = base.enabled !== false && matrixBase.enabled !== false;
|
|
161
|
+
|
|
162
|
+
const authView = resolveMatrixAccountAuthView({
|
|
163
|
+
cfg: params.cfg,
|
|
164
|
+
accountId,
|
|
165
|
+
env,
|
|
166
|
+
});
|
|
167
|
+
const hasHomeserver = Boolean(authView.homeserver);
|
|
168
|
+
const hasUserId = Boolean(authView.userId);
|
|
169
|
+
const hasAccessToken =
|
|
170
|
+
Boolean(authView.accessToken) || hasConfiguredSecretInput(explicitAuthConfig.accessToken);
|
|
171
|
+
const hasPassword = Boolean(authView.password);
|
|
172
|
+
const hasPasswordAuth =
|
|
173
|
+
hasUserId && (hasPassword || hasConfiguredSecretInput(explicitAuthConfig.password));
|
|
174
|
+
const stored = loadMatrixCredentials(env, accountId);
|
|
175
|
+
const hasStored =
|
|
176
|
+
stored && authView.homeserver
|
|
177
|
+
? credentialsMatchConfig(stored, {
|
|
178
|
+
homeserver: authView.homeserver,
|
|
179
|
+
userId: authView.userId || "",
|
|
180
|
+
})
|
|
181
|
+
: false;
|
|
182
|
+
const configured = hasHomeserver && (hasAccessToken || hasPasswordAuth || hasStored);
|
|
183
|
+
return {
|
|
184
|
+
accountId,
|
|
185
|
+
enabled,
|
|
186
|
+
name: normalizeOptionalString(base.name),
|
|
187
|
+
configured,
|
|
188
|
+
homeserver: authView.homeserver || undefined,
|
|
189
|
+
userId: authView.userId || undefined,
|
|
190
|
+
config: base,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export { resolveMatrixAccountConfig } from "./account-config.js";
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
createMockMatrixClient,
|
|
4
|
+
expectExplicitMatrixClientConfig,
|
|
5
|
+
expectOneOffSharedMatrixClient,
|
|
6
|
+
matrixClientResolverMocks,
|
|
7
|
+
primeMatrixClientResolverMocks,
|
|
8
|
+
} from "../client-resolver.test-helpers.js";
|
|
9
|
+
|
|
10
|
+
const resolveMatrixRoomIdMock = vi.fn();
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
loadConfigMock,
|
|
14
|
+
getMatrixRuntimeMock,
|
|
15
|
+
getActiveMatrixClientMock,
|
|
16
|
+
acquireSharedMatrixClientMock,
|
|
17
|
+
releaseSharedClientInstanceMock,
|
|
18
|
+
isBunRuntimeMock,
|
|
19
|
+
resolveMatrixAuthContextMock,
|
|
20
|
+
} = matrixClientResolverMocks;
|
|
21
|
+
|
|
22
|
+
vi.mock("../../runtime.js", () => ({
|
|
23
|
+
getMatrixRuntime: () => getMatrixRuntimeMock(),
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
vi.mock("../active-client.js", () => ({
|
|
27
|
+
getActiveMatrixClient: getActiveMatrixClientMock,
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
vi.mock("../client.js", () => ({
|
|
31
|
+
acquireSharedMatrixClient: acquireSharedMatrixClientMock,
|
|
32
|
+
isBunRuntime: () => isBunRuntimeMock(),
|
|
33
|
+
resolveMatrixAuthContext: resolveMatrixAuthContextMock,
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
vi.mock("../client/shared.js", () => ({
|
|
37
|
+
releaseSharedClientInstance: (...args: unknown[]) => releaseSharedClientInstanceMock(...args),
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
vi.mock("../send.js", () => ({
|
|
41
|
+
resolveMatrixRoomId: (...args: unknown[]) => resolveMatrixRoomIdMock(...args),
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
let withResolvedActionClient: typeof import("./client.js").withResolvedActionClient;
|
|
45
|
+
let withResolvedRoomAction: typeof import("./client.js").withResolvedRoomAction;
|
|
46
|
+
let withStartedActionClient: typeof import("./client.js").withStartedActionClient;
|
|
47
|
+
|
|
48
|
+
describe("action client helpers", () => {
|
|
49
|
+
beforeAll(async () => {
|
|
50
|
+
({ withResolvedActionClient, withResolvedRoomAction, withStartedActionClient } =
|
|
51
|
+
await import("./client.js"));
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
primeMatrixClientResolverMocks();
|
|
56
|
+
resolveMatrixRoomIdMock
|
|
57
|
+
.mockReset()
|
|
58
|
+
.mockImplementation(async (_client, roomId: string) => roomId);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
afterEach(() => {
|
|
62
|
+
vi.unstubAllEnvs();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("stops one-off shared clients when no active monitor client is registered", async () => {
|
|
66
|
+
vi.stubEnv("OPENCLAW_GATEWAY_PORT", "18799");
|
|
67
|
+
|
|
68
|
+
const result = await withResolvedActionClient({ accountId: "default" }, async () => "ok");
|
|
69
|
+
|
|
70
|
+
await expectOneOffSharedMatrixClient();
|
|
71
|
+
expect(result).toBe("ok");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("skips one-off room preparation when readiness is disabled", async () => {
|
|
75
|
+
await withResolvedActionClient({ accountId: "default", readiness: "none" }, async () => {});
|
|
76
|
+
|
|
77
|
+
const sharedClient = await acquireSharedMatrixClientMock.mock.results[0]?.value;
|
|
78
|
+
expect(sharedClient.prepareForOneOff).not.toHaveBeenCalled();
|
|
79
|
+
expect(sharedClient.start).not.toHaveBeenCalled();
|
|
80
|
+
expect(releaseSharedClientInstanceMock).toHaveBeenCalledWith(sharedClient, "stop");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("starts one-off clients when started readiness is required", async () => {
|
|
84
|
+
await withStartedActionClient({ accountId: "default" }, async () => {});
|
|
85
|
+
|
|
86
|
+
const sharedClient = await acquireSharedMatrixClientMock.mock.results[0]?.value;
|
|
87
|
+
expect(sharedClient.start).toHaveBeenCalledTimes(1);
|
|
88
|
+
expect(sharedClient.prepareForOneOff).not.toHaveBeenCalled();
|
|
89
|
+
expect(releaseSharedClientInstanceMock).toHaveBeenCalledWith(sharedClient, "persist");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("reuses active monitor client when available", async () => {
|
|
93
|
+
const activeClient = createMockMatrixClient();
|
|
94
|
+
getActiveMatrixClientMock.mockReturnValue(activeClient);
|
|
95
|
+
|
|
96
|
+
const result = await withResolvedActionClient({ accountId: "default" }, async (client) => {
|
|
97
|
+
expect(client).toBe(activeClient);
|
|
98
|
+
return "ok";
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(result).toBe("ok");
|
|
102
|
+
expect(acquireSharedMatrixClientMock).not.toHaveBeenCalled();
|
|
103
|
+
expect(activeClient.stop).not.toHaveBeenCalled();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("starts active clients when started readiness is required", async () => {
|
|
107
|
+
const activeClient = createMockMatrixClient();
|
|
108
|
+
getActiveMatrixClientMock.mockReturnValue(activeClient);
|
|
109
|
+
|
|
110
|
+
await withStartedActionClient({ accountId: "default" }, async (client) => {
|
|
111
|
+
expect(client).toBe(activeClient);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
expect(activeClient.start).toHaveBeenCalledTimes(1);
|
|
115
|
+
expect(activeClient.prepareForOneOff).not.toHaveBeenCalled();
|
|
116
|
+
expect(activeClient.stop).not.toHaveBeenCalled();
|
|
117
|
+
expect(activeClient.stopAndPersist).not.toHaveBeenCalled();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("uses the implicit resolved account id for active client lookup and storage", async () => {
|
|
121
|
+
loadConfigMock.mockReturnValue({
|
|
122
|
+
channels: {
|
|
123
|
+
matrix: {
|
|
124
|
+
accounts: {
|
|
125
|
+
ops: {
|
|
126
|
+
homeserver: "https://ops.example.org",
|
|
127
|
+
userId: "@ops:example.org",
|
|
128
|
+
accessToken: "ops-token",
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
resolveMatrixAuthContextMock.mockReturnValue({
|
|
135
|
+
cfg: loadConfigMock(),
|
|
136
|
+
env: process.env,
|
|
137
|
+
accountId: "ops",
|
|
138
|
+
resolved: {
|
|
139
|
+
homeserver: "https://ops.example.org",
|
|
140
|
+
userId: "@ops:example.org",
|
|
141
|
+
accessToken: "ops-token",
|
|
142
|
+
deviceId: "OPSDEVICE",
|
|
143
|
+
encryption: true,
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
await withResolvedActionClient({}, async () => {});
|
|
147
|
+
|
|
148
|
+
await expectOneOffSharedMatrixClient({
|
|
149
|
+
cfg: loadConfigMock(),
|
|
150
|
+
accountId: "ops",
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("uses explicit cfg instead of loading runtime config", async () => {
|
|
155
|
+
const explicitCfg = {
|
|
156
|
+
channels: {
|
|
157
|
+
matrix: {
|
|
158
|
+
defaultAccount: "ops",
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
await withResolvedActionClient({ cfg: explicitCfg, accountId: "ops" }, async () => {});
|
|
164
|
+
|
|
165
|
+
expectExplicitMatrixClientConfig({
|
|
166
|
+
cfg: explicitCfg,
|
|
167
|
+
accountId: "ops",
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("stops shared action clients after wrapped calls succeed", async () => {
|
|
172
|
+
const sharedClient = createMockMatrixClient();
|
|
173
|
+
acquireSharedMatrixClientMock.mockResolvedValue(sharedClient);
|
|
174
|
+
|
|
175
|
+
const result = await withResolvedActionClient({ accountId: "default" }, async (client) => {
|
|
176
|
+
expect(client).toBe(sharedClient);
|
|
177
|
+
return "ok";
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
expect(result).toBe("ok");
|
|
181
|
+
expect(releaseSharedClientInstanceMock).toHaveBeenCalledWith(sharedClient, "stop");
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("stops shared action clients when the wrapped call throws", async () => {
|
|
185
|
+
const sharedClient = createMockMatrixClient();
|
|
186
|
+
acquireSharedMatrixClientMock.mockResolvedValue(sharedClient);
|
|
187
|
+
|
|
188
|
+
await expect(
|
|
189
|
+
withResolvedActionClient({ accountId: "default" }, async () => {
|
|
190
|
+
throw new Error("boom");
|
|
191
|
+
}),
|
|
192
|
+
).rejects.toThrow("boom");
|
|
193
|
+
|
|
194
|
+
expect(releaseSharedClientInstanceMock).toHaveBeenCalledWith(sharedClient, "stop");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("resolves room ids before running wrapped room actions", async () => {
|
|
198
|
+
const sharedClient = createMockMatrixClient();
|
|
199
|
+
acquireSharedMatrixClientMock.mockResolvedValue(sharedClient);
|
|
200
|
+
resolveMatrixRoomIdMock.mockResolvedValue("!room:example.org");
|
|
201
|
+
|
|
202
|
+
const result = await withResolvedRoomAction(
|
|
203
|
+
"room:#ops:example.org",
|
|
204
|
+
{ accountId: "default" },
|
|
205
|
+
async (client, resolvedRoom) => {
|
|
206
|
+
expect(client).toBe(sharedClient);
|
|
207
|
+
return resolvedRoom;
|
|
208
|
+
},
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
expect(resolveMatrixRoomIdMock).toHaveBeenCalledWith(sharedClient, "room:#ops:example.org");
|
|
212
|
+
expect(result).toBe("!room:example.org");
|
|
213
|
+
expect(releaseSharedClientInstanceMock).toHaveBeenCalledWith(sharedClient, "stop");
|
|
214
|
+
});
|
|
215
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { withResolvedRuntimeMatrixClient } from "../client-bootstrap.js";
|
|
2
|
+
import { resolveMatrixRoomId } from "../send.js";
|
|
3
|
+
import type { MatrixActionClient, MatrixActionClientOpts } from "./types.js";
|
|
4
|
+
|
|
5
|
+
type MatrixActionClientStopMode = "stop" | "persist";
|
|
6
|
+
|
|
7
|
+
export async function withResolvedActionClient<T>(
|
|
8
|
+
opts: MatrixActionClientOpts,
|
|
9
|
+
run: (client: MatrixActionClient["client"]) => Promise<T>,
|
|
10
|
+
mode: MatrixActionClientStopMode = "stop",
|
|
11
|
+
): Promise<T> {
|
|
12
|
+
return await withResolvedRuntimeMatrixClient(opts, run, mode);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function withStartedActionClient<T>(
|
|
16
|
+
opts: MatrixActionClientOpts,
|
|
17
|
+
run: (client: MatrixActionClient["client"]) => Promise<T>,
|
|
18
|
+
): Promise<T> {
|
|
19
|
+
return await withResolvedActionClient({ ...opts, readiness: "started" }, run, "persist");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function withResolvedRoomAction<T>(
|
|
23
|
+
roomId: string,
|
|
24
|
+
opts: MatrixActionClientOpts,
|
|
25
|
+
run: (client: MatrixActionClient["client"], resolvedRoom: string) => Promise<T>,
|
|
26
|
+
): Promise<T> {
|
|
27
|
+
return await withResolvedActionClient(opts, async (client) => {
|
|
28
|
+
const resolvedRoom = await resolveMatrixRoomId(client, roomId);
|
|
29
|
+
return await run(client, resolvedRoom);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
const withStartedActionClientMock = vi.fn();
|
|
4
|
+
|
|
5
|
+
vi.mock("./client.js", () => ({
|
|
6
|
+
withStartedActionClient: (...args: unknown[]) => withStartedActionClientMock(...args),
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
const { listMatrixOwnDevices, pruneMatrixStaleGatewayDevices } = await import("./devices.js");
|
|
10
|
+
|
|
11
|
+
describe("matrix device actions", () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("lists own devices on a started client", async () => {
|
|
17
|
+
withStartedActionClientMock.mockImplementation(async (_opts, run) => {
|
|
18
|
+
return await run({
|
|
19
|
+
listOwnDevices: vi.fn(async () => [
|
|
20
|
+
{
|
|
21
|
+
deviceId: "A7hWrQ70ea",
|
|
22
|
+
displayName: "OpenClaw Gateway",
|
|
23
|
+
lastSeenIp: null,
|
|
24
|
+
lastSeenTs: null,
|
|
25
|
+
current: true,
|
|
26
|
+
},
|
|
27
|
+
]),
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const result = await listMatrixOwnDevices({ accountId: "poe" });
|
|
32
|
+
|
|
33
|
+
expect(withStartedActionClientMock).toHaveBeenCalledWith(
|
|
34
|
+
{ accountId: "poe" },
|
|
35
|
+
expect.any(Function),
|
|
36
|
+
);
|
|
37
|
+
expect(result).toEqual([
|
|
38
|
+
expect.objectContaining({
|
|
39
|
+
deviceId: "A7hWrQ70ea",
|
|
40
|
+
current: true,
|
|
41
|
+
}),
|
|
42
|
+
]);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("prunes stale OpenClaw-managed devices but preserves the current device", async () => {
|
|
46
|
+
const deleteOwnDevices = vi.fn(async () => ({
|
|
47
|
+
currentDeviceId: "du314Zpw3A",
|
|
48
|
+
deletedDeviceIds: ["BritdXC6iL", "G6NJU9cTgs", "My3T0hkTE0"],
|
|
49
|
+
remainingDevices: [
|
|
50
|
+
{
|
|
51
|
+
deviceId: "du314Zpw3A",
|
|
52
|
+
displayName: "OpenClaw Gateway",
|
|
53
|
+
lastSeenIp: null,
|
|
54
|
+
lastSeenTs: null,
|
|
55
|
+
current: true,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
}));
|
|
59
|
+
withStartedActionClientMock.mockImplementation(async (_opts, run) => {
|
|
60
|
+
return await run({
|
|
61
|
+
listOwnDevices: vi.fn(async () => [
|
|
62
|
+
{
|
|
63
|
+
deviceId: "du314Zpw3A",
|
|
64
|
+
displayName: "OpenClaw Gateway",
|
|
65
|
+
lastSeenIp: null,
|
|
66
|
+
lastSeenTs: null,
|
|
67
|
+
current: true,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
deviceId: "BritdXC6iL",
|
|
71
|
+
displayName: "OpenClaw Gateway",
|
|
72
|
+
lastSeenIp: null,
|
|
73
|
+
lastSeenTs: null,
|
|
74
|
+
current: false,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
deviceId: "G6NJU9cTgs",
|
|
78
|
+
displayName: "OpenClaw Debug",
|
|
79
|
+
lastSeenIp: null,
|
|
80
|
+
lastSeenTs: null,
|
|
81
|
+
current: false,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
deviceId: "My3T0hkTE0",
|
|
85
|
+
displayName: "OpenClaw Gateway",
|
|
86
|
+
lastSeenIp: null,
|
|
87
|
+
lastSeenTs: null,
|
|
88
|
+
current: false,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
deviceId: "phone123",
|
|
92
|
+
displayName: "Element iPhone",
|
|
93
|
+
lastSeenIp: null,
|
|
94
|
+
lastSeenTs: null,
|
|
95
|
+
current: false,
|
|
96
|
+
},
|
|
97
|
+
]),
|
|
98
|
+
deleteOwnDevices,
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const result = await pruneMatrixStaleGatewayDevices({ accountId: "poe" });
|
|
103
|
+
|
|
104
|
+
expect(deleteOwnDevices).toHaveBeenCalledWith(["BritdXC6iL", "G6NJU9cTgs", "My3T0hkTE0"]);
|
|
105
|
+
expect(result.staleGatewayDeviceIds).toEqual(["BritdXC6iL", "G6NJU9cTgs", "My3T0hkTE0"]);
|
|
106
|
+
expect(result.deletedDeviceIds).toEqual(["BritdXC6iL", "G6NJU9cTgs", "My3T0hkTE0"]);
|
|
107
|
+
expect(result.remainingDevices).toEqual([
|
|
108
|
+
expect.objectContaining({
|
|
109
|
+
deviceId: "du314Zpw3A",
|
|
110
|
+
current: true,
|
|
111
|
+
}),
|
|
112
|
+
]);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { summarizeMatrixDeviceHealth } from "../device-health.js";
|
|
2
|
+
import { withStartedActionClient } from "./client.js";
|
|
3
|
+
import type { MatrixActionClientOpts } from "./types.js";
|
|
4
|
+
|
|
5
|
+
export async function listMatrixOwnDevices(opts: MatrixActionClientOpts = {}) {
|
|
6
|
+
return await withStartedActionClient(opts, async (client) => await client.listOwnDevices());
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function pruneMatrixStaleGatewayDevices(opts: MatrixActionClientOpts = {}) {
|
|
10
|
+
return await withStartedActionClient(opts, async (client) => {
|
|
11
|
+
const devices = await client.listOwnDevices();
|
|
12
|
+
const health = summarizeMatrixDeviceHealth(devices);
|
|
13
|
+
const staleGatewayDeviceIds = health.staleOpenClawDevices.map((device) => device.deviceId);
|
|
14
|
+
const deleted =
|
|
15
|
+
staleGatewayDeviceIds.length > 0
|
|
16
|
+
? await client.deleteOwnDevices(staleGatewayDeviceIds)
|
|
17
|
+
: {
|
|
18
|
+
currentDeviceId: devices.find((device) => device.current)?.deviceId ?? null,
|
|
19
|
+
deletedDeviceIds: [] as string[],
|
|
20
|
+
remainingDevices: devices,
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
before: devices,
|
|
24
|
+
staleGatewayDeviceIds,
|
|
25
|
+
...deleted,
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function getMatrixDeviceHealth(opts: MatrixActionClientOpts = {}) {
|
|
31
|
+
return await withStartedActionClient(opts, async (client) =>
|
|
32
|
+
summarizeMatrixDeviceHealth(await client.listOwnDevices()),
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { resolveMatrixActionLimit } from "./limits.js";
|
|
3
|
+
|
|
4
|
+
describe("resolveMatrixActionLimit", () => {
|
|
5
|
+
it("uses fallback for non-finite values", () => {
|
|
6
|
+
expect(resolveMatrixActionLimit(undefined, 20)).toBe(20);
|
|
7
|
+
expect(resolveMatrixActionLimit(Number.NaN, 20)).toBe(20);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("normalizes finite numbers to positive integers", () => {
|
|
11
|
+
expect(resolveMatrixActionLimit(7.9, 20)).toBe(7);
|
|
12
|
+
expect(resolveMatrixActionLimit(0, 20)).toBe(1);
|
|
13
|
+
expect(resolveMatrixActionLimit(-3, 20)).toBe(1);
|
|
14
|
+
});
|
|
15
|
+
});
|