diff --git a/extensions/matrix/src/actions.test.ts b/extensions/matrix/src/actions.test.ts index f9da97881ac..df34411b806 100644 --- a/extensions/matrix/src/actions.test.ts +++ b/extensions/matrix/src/actions.test.ts @@ -59,7 +59,7 @@ describe("matrixMessageActions", () => { const discovery = describeMessageTool!({ cfg: createConfiguredMatrixConfig(), - } as never); + } as never) ?? { actions: [] }; const actions = discovery.actions; expect(actions).toContain("poll"); @@ -74,7 +74,7 @@ describe("matrixMessageActions", () => { const discovery = describeMessageTool!({ cfg: createConfiguredMatrixConfig(), - } as never); + } as never) ?? { actions: [], schema: null }; const actions = discovery.actions; const properties = (discovery.schema as { properties?: Record } | null)?.properties ?? {}; @@ -87,64 +87,66 @@ describe("matrixMessageActions", () => { }); it("hides gated actions when the default Matrix account disables them", () => { - const actions = matrixMessageActions.describeMessageTool!({ - cfg: { - channels: { - matrix: { - defaultAccount: "assistant", - actions: { - messages: true, - reactions: true, - pins: true, - profile: true, - memberInfo: true, - channelInfo: true, - verification: true, - }, - accounts: { - assistant: { - homeserver: "https://matrix.example.org", - userId: "@bot:example.org", - accessToken: "token", - encryption: true, - actions: { - messages: false, - reactions: false, - pins: false, - profile: false, - memberInfo: false, - channelInfo: false, - verification: false, + const actions = + matrixMessageActions.describeMessageTool!({ + cfg: { + channels: { + matrix: { + defaultAccount: "assistant", + actions: { + messages: true, + reactions: true, + pins: true, + profile: true, + memberInfo: true, + channelInfo: true, + verification: true, + }, + accounts: { + assistant: { + homeserver: "https://matrix.example.org", + userId: "@bot:example.org", + accessToken: "token", + encryption: true, + actions: { + messages: false, + reactions: false, + pins: false, + profile: false, + memberInfo: false, + channelInfo: false, + verification: false, + }, }, }, }, }, - }, - } as CoreConfig, - } as never).actions; + } as CoreConfig, + } as never)?.actions ?? []; expect(actions).toEqual(["poll", "poll-vote"]); }); it("hides actions until defaultAccount is set for ambiguous multi-account configs", () => { - const actions = matrixMessageActions.describeMessageTool!({ - cfg: { - channels: { - matrix: { - accounts: { - assistant: { - homeserver: "https://matrix.example.org", - accessToken: "assistant-token", - }, - ops: { - homeserver: "https://matrix.example.org", - accessToken: "ops-token", + const actions = + matrixMessageActions.describeMessageTool!({ + cfg: { + channels: { + matrix: { + accounts: { + assistant: { + homeserver: "https://matrix.example.org", + accessToken: "assistant-token", + }, + ops: { + homeserver: "https://matrix.example.org", + accessToken: "ops-token", + }, }, }, }, - }, - } as CoreConfig, - } as never).actions; + } as CoreConfig, + } as never)?.actions ?? []; expect(actions).toEqual([]); }); diff --git a/extensions/matrix/src/channel.runtime.ts b/extensions/matrix/src/channel.runtime.ts index e75d06f1875..e3d8c9d05c5 100644 --- a/extensions/matrix/src/channel.runtime.ts +++ b/extensions/matrix/src/channel.runtime.ts @@ -2,11 +2,13 @@ import { listMatrixDirectoryGroupsLive, listMatrixDirectoryPeersLive } from "./d import { resolveMatrixAuth } from "./matrix/client.js"; import { probeMatrix } from "./matrix/probe.js"; import { sendMessageMatrix } from "./matrix/send.js"; +import { matrixOutbound } from "./outbound.js"; import { resolveMatrixTargets } from "./resolve-targets.js"; export const matrixChannelRuntime = { listMatrixDirectoryGroupsLive, listMatrixDirectoryPeersLive, + matrixOutbound, probeMatrix, resolveMatrixAuth, resolveMatrixTargets, diff --git a/extensions/matrix/src/channel.ts b/extensions/matrix/src/channel.ts index cf251450fd2..cfc4ccdddf1 100644 --- a/extensions/matrix/src/channel.ts +++ b/extensions/matrix/src/channel.ts @@ -15,8 +15,8 @@ import { createTextPairingAdapter, listResolvedDirectoryEntriesFromSources, } from "openclaw/plugin-sdk/channel-runtime"; +import { buildTrafficStatusSummary } from "openclaw/plugin-sdk/extension-shared"; import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime"; -import { buildTrafficStatusSummary } from "../../shared/channel-status-summary.js"; import { buildChannelConfigSchema, buildProbeChannelStatusSummary, @@ -47,7 +47,6 @@ import { import { getMatrixRuntime } from "./runtime.js"; import { resolveMatrixOutboundSessionRoute } from "./session-route.js"; import { matrixSetupAdapter } from "./setup-core.js"; -import { matrixSetupWizard } from "./setup-surface.js"; import type { CoreConfig } from "./types.js"; // Mutex for serializing account startup (workaround for concurrent dynamic import race condition) @@ -190,7 +189,6 @@ function matchMatrixAcpConversation(params: { export const matrixPlugin: ChannelPlugin = { id: "matrix", meta, - setupWizard: matrixSetupWizard, pairing: createTextPairingAdapter({ idLabel: "matrixUserId", message: PAIRING_APPROVED_MESSAGE, diff --git a/extensions/matrix/src/cli.test.ts b/extensions/matrix/src/cli.test.ts index a97c083ebce..008fd46795d 100644 --- a/extensions/matrix/src/cli.test.ts +++ b/extensions/matrix/src/cli.test.ts @@ -521,7 +521,9 @@ describe("matrix CLI verification commands", () => { expect(matrixRuntimeWriteConfigFileMock).toHaveBeenCalled(); expect(process.exitCode).toBeUndefined(); - const jsonOutput = console.log.mock.calls.at(-1)?.[0]; + const jsonOutput = (console.log as unknown as { mock: { calls: unknown[][] } }).mock.calls.at( + -1, + )?.[0]; expect(typeof jsonOutput).toBe("string"); expect(JSON.parse(String(jsonOutput))).toEqual( expect.objectContaining({ diff --git a/extensions/matrix/src/matrix/client/file-sync-store.test.ts b/extensions/matrix/src/matrix/client/file-sync-store.test.ts index 85d61580a17..5bda781b5b2 100644 --- a/extensions/matrix/src/matrix/client/file-sync-store.test.ts +++ b/extensions/matrix/src/matrix/client/file-sync-store.test.ts @@ -12,7 +12,7 @@ function createSyncResponse(nextBatch: string): ISyncResponse { rooms: { join: { "!room:example.org": { - summary: {}, + summary: { "m.heroes": [] }, state: { events: [] }, timeline: { events: [ @@ -34,6 +34,9 @@ function createSyncResponse(nextBatch: string): ISyncResponse { unread_notifications: {}, }, }, + invite: {}, + leave: {}, + knock: {}, }, account_data: { events: [ diff --git a/extensions/matrix/src/matrix/client/file-sync-store.ts b/extensions/matrix/src/matrix/client/file-sync-store.ts index 9f1d0599569..411f4e0decd 100644 --- a/extensions/matrix/src/matrix/client/file-sync-store.ts +++ b/extensions/matrix/src/matrix/client/file-sync-store.ts @@ -52,7 +52,7 @@ function toPersistedSyncData(value: unknown): ISyncData | null { nextBatch: value.nextBatch, accountData: value.accountData, roomsData: value.roomsData, - } as ISyncData; + } as unknown as ISyncData; } // Older Matrix state files stored the raw /sync-shaped payload directly. @@ -64,7 +64,7 @@ function toPersistedSyncData(value: unknown): ISyncData | null { ? value.account_data.events : [], roomsData: isRecord(value.rooms) ? value.rooms : {}, - } as ISyncData; + } as unknown as ISyncData; } return null; diff --git a/extensions/matrix/src/matrix/index.ts b/extensions/matrix/src/matrix/index.ts new file mode 100644 index 00000000000..9795b10c1a6 --- /dev/null +++ b/extensions/matrix/src/matrix/index.ts @@ -0,0 +1 @@ +export { monitorMatrixProvider } from "./monitor/index.js"; diff --git a/extensions/matrix/src/matrix/monitor/events.test.ts b/extensions/matrix/src/matrix/monitor/events.test.ts index 0f8480424b5..5d4642bdb5e 100644 --- a/extensions/matrix/src/matrix/monitor/events.test.ts +++ b/extensions/matrix/src/matrix/monitor/events.test.ts @@ -62,7 +62,7 @@ function createHarness(params?: { const ensureVerificationDmTracked = vi.fn( params?.ensureVerificationDmTracked ?? (async () => null), ); - const sendMessage = vi.fn(async () => "$notice"); + const sendMessage = vi.fn(async (_roomId: string, _payload: { body?: string }) => "$notice"); const invalidateRoom = vi.fn(); const logger = { info: vi.fn(), warn: vi.fn(), error: vi.fn() }; const formatNativeDependencyHint = vi.fn(() => "install hint"); diff --git a/extensions/matrix/src/matrix/monitor/handler.media-failure.test.ts b/extensions/matrix/src/matrix/monitor/handler.media-failure.test.ts index e1fc7e969ca..25f17cb0254 100644 --- a/extensions/matrix/src/matrix/monitor/handler.media-failure.test.ts +++ b/extensions/matrix/src/matrix/monitor/handler.media-failure.test.ts @@ -100,6 +100,7 @@ function createHandlerHarness() { mediaMaxBytes: 5 * 1024 * 1024, startupMs: Date.now() - 120_000, startupGraceMs: 60_000, + dropPreStartupMessages: false, directTracker: { isDirectMessage: vi.fn().mockResolvedValue(true), }, diff --git a/extensions/matrix/src/matrix/monitor/handler.test.ts b/extensions/matrix/src/matrix/monitor/handler.test.ts index 2a627c0fc0e..e28afdff33d 100644 --- a/extensions/matrix/src/matrix/monitor/handler.test.ts +++ b/extensions/matrix/src/matrix/monitor/handler.test.ts @@ -588,11 +588,13 @@ describe("matrix monitor handler pairing account scope", () => { mediaMaxBytes: 10_000_000, startupMs: 0, startupGraceMs: 0, + dropPreStartupMessages: false, directTracker: { isDirectMessage: async () => false, }, getRoomInfo: async () => ({ altAliases: [] }), getMemberDisplayName: async () => "sender", + needsRoomAliasesForConfig: false, }); await handler( diff --git a/extensions/matrix/src/matrix/monitor/handler.thread-root-media.test.ts b/extensions/matrix/src/matrix/monitor/handler.thread-root-media.test.ts index 7dfbcebe401..c08452cd76b 100644 --- a/extensions/matrix/src/matrix/monitor/handler.thread-root-media.test.ts +++ b/extensions/matrix/src/matrix/monitor/handler.thread-root-media.test.ts @@ -115,6 +115,7 @@ describe("createMatrixRoomMessageHandler thread root media", () => { mediaMaxBytes: 5 * 1024 * 1024, startupMs: Date.now() - 120_000, startupGraceMs: 60_000, + dropPreStartupMessages: false, directTracker: { isDirectMessage: vi.fn().mockResolvedValue(true), }, diff --git a/extensions/matrix/src/matrix/monitor/index.test.ts b/extensions/matrix/src/matrix/monitor/index.test.ts index 30d7a6d4890..6d6779de445 100644 --- a/extensions/matrix/src/matrix/monitor/index.test.ts +++ b/extensions/matrix/src/matrix/monitor/index.test.ts @@ -7,7 +7,6 @@ const hoisted = vi.hoisted(() => { hasPersistedSyncState: vi.fn(() => false), }; const createMatrixRoomMessageHandler = vi.fn(() => vi.fn()); - let startClientError: Error | null = null; const resolveTextChunkLimit = vi.fn< (cfg: unknown, channel: unknown, accountId?: unknown) => number >(() => 4000); @@ -27,7 +26,7 @@ const hoisted = vi.hoisted(() => { logger, resolveTextChunkLimit, setActiveMatrixClient, - startClientError, + startClientError: null as Error | null, stopSharedClientInstance, stopThreadBindingManager, }; diff --git a/extensions/matrix/src/matrix/monitor/route.test.ts b/extensions/matrix/src/matrix/monitor/route.test.ts index 3b64f3e4491..5846d45dd9c 100644 --- a/extensions/matrix/src/matrix/monitor/route.test.ts +++ b/extensions/matrix/src/matrix/monitor/route.test.ts @@ -1,12 +1,12 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { OpenClawConfig } from "../../../../../src/config/config.js"; import { - __testing as sessionBindingTesting, + createTestRegistry, + type OpenClawConfig, + resolveAgentRoute, registerSessionBindingAdapter, -} from "../../../../../src/infra/outbound/session-binding-service.js"; -import { setActivePluginRegistry } from "../../../../../src/plugins/runtime.js"; -import { resolveAgentRoute } from "../../../../../src/routing/resolve-route.js"; -import { createTestRegistry } from "../../../../../src/test-utils/channel-plugins.js"; + sessionBindingTesting, + setActivePluginRegistry, +} from "../../../../../test/helpers/extensions/matrix-route-test.js"; import { matrixPlugin } from "../../channel.js"; import { resolveMatrixInboundRoute } from "./route.js"; diff --git a/extensions/matrix/src/matrix/sdk.test.ts b/extensions/matrix/src/matrix/sdk.test.ts index 3467f12711c..e25d215af05 100644 --- a/extensions/matrix/src/matrix/sdk.test.ts +++ b/extensions/matrix/src/matrix/sdk.test.ts @@ -222,7 +222,10 @@ describe("MatrixClient request hardening", () => { it("prefers authenticated client media downloads", async () => { const payload = Buffer.from([1, 2, 3, 4]); - const fetchMock = vi.fn(async () => new Response(payload, { status: 200 })); + const fetchMock = vi.fn( + async (_input: RequestInfo | URL, _init?: RequestInit) => + new Response(payload, { status: 200 }), + ); vi.stubGlobal("fetch", fetchMock as unknown as typeof fetch); const client = new MatrixClient("https://matrix.example.org", "token"); diff --git a/extensions/matrix/src/matrix/sdk.ts b/extensions/matrix/src/matrix/sdk.ts index 94ac1990096..b2084e5c210 100644 --- a/extensions/matrix/src/matrix/sdk.ts +++ b/extensions/matrix/src/matrix/sdk.ts @@ -4,6 +4,7 @@ import { EventEmitter } from "node:events"; import { ClientEvent, MatrixEventEvent, + Preset, createClient as createMatrixJsClient, type MatrixClient as MatrixJsClient, type MatrixEvent, @@ -547,7 +548,7 @@ export class MatrixClient { const result = await this.client.createRoom({ invite: [remoteUserId], is_direct: true, - preset: "trusted_private_chat", + preset: Preset.TrustedPrivateChat, initial_state: initialState, }); return result.room_id; diff --git a/extensions/matrix/src/matrix/thread-bindings.ts b/extensions/matrix/src/matrix/thread-bindings.ts index d69e477a20a..eb9a7e4c1d9 100644 --- a/extensions/matrix/src/matrix/thread-bindings.ts +++ b/extensions/matrix/src/matrix/thread-bindings.ts @@ -621,14 +621,6 @@ export async function createMatrixThreadBindingManager(params: { }); return record ? toSessionBindingRecord(record, defaults) : null; }, - setIdleTimeoutBySession: ({ targetSessionKey, idleTimeoutMs }) => - manager - .setIdleTimeoutBySessionKey({ targetSessionKey, idleTimeoutMs }) - .map((record) => toSessionBindingRecord(record, defaults)), - setMaxAgeBySession: ({ targetSessionKey, maxAgeMs }) => - manager - .setMaxAgeBySessionKey({ targetSessionKey, maxAgeMs }) - .map((record) => toSessionBindingRecord(record, defaults)), touch: (bindingId, at) => { manager.touchBinding(bindingId, at); }, diff --git a/extensions/matrix/src/onboarding.ts b/extensions/matrix/src/onboarding.ts index 62fe0613524..01e60ba53eb 100644 --- a/extensions/matrix/src/onboarding.ts +++ b/extensions/matrix/src/onboarding.ts @@ -1,8 +1,5 @@ import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id"; -import { - type ChannelSetupDmPolicy, - type ChannelSetupWizardAdapter, -} from "openclaw/plugin-sdk/setup"; +import { type ChannelSetupDmPolicy } from "openclaw/plugin-sdk/setup"; import { requiresExplicitMatrixDefaultAccount } from "./account-selection.js"; import { listMatrixDirectoryGroupsLive } from "./directory-live.js"; import { @@ -36,6 +33,54 @@ import type { CoreConfig } from "./types.js"; const channel = "matrix" as const; +type MatrixOnboardingStatus = { + channel: typeof channel; + configured: boolean; + statusLines: string[]; + selectionHint?: string; + quickstartScore?: number; +}; + +type MatrixAccountOverrides = Partial>; + +type MatrixOnboardingConfigureContext = { + cfg: CoreConfig; + runtime: RuntimeEnv; + prompter: WizardPrompter; + options?: unknown; + forceAllowFrom: boolean; + accountOverrides: MatrixAccountOverrides; + shouldPromptAccountIds: boolean; +}; + +type MatrixOnboardingInteractiveContext = MatrixOnboardingConfigureContext & { + configured: boolean; + label?: string; +}; + +type MatrixOnboardingAdapter = { + channel: typeof channel; + getStatus: (ctx: { + cfg: CoreConfig; + options?: unknown; + accountOverrides: MatrixAccountOverrides; + }) => Promise; + configure: ( + ctx: MatrixOnboardingConfigureContext, + ) => Promise<{ cfg: CoreConfig; accountId?: string }>; + configureInteractive?: ( + ctx: MatrixOnboardingInteractiveContext, + ) => Promise<{ cfg: CoreConfig; accountId?: string } | "skip">; + afterConfigWritten?: (ctx: { + previousCfg: CoreConfig; + cfg: CoreConfig; + accountId: string; + runtime: RuntimeEnv; + }) => Promise | void; + dmPolicy?: ChannelSetupDmPolicy; + disable?: (cfg: CoreConfig) => CoreConfig; +}; + function resolveMatrixOnboardingAccountId(cfg: CoreConfig, accountId?: string): string { return normalizeAccountId( accountId?.trim() || resolveDefaultMatrixAccountId(cfg) || DEFAULT_ACCOUNT_ID, @@ -473,7 +518,7 @@ async function runMatrixConfigure(params: { return { cfg: next, accountId }; } -export const matrixOnboardingAdapter: ChannelSetupWizardAdapter = { +export const matrixOnboardingAdapter: MatrixOnboardingAdapter = { channel, getStatus: async ({ cfg, accountOverrides }) => { const resolvedCfg = cfg as CoreConfig; diff --git a/src/agents/acp-spawn.test.ts b/src/agents/acp-spawn.test.ts index d11b569602c..3b93bf0a826 100644 --- a/src/agents/acp-spawn.test.ts +++ b/src/agents/acp-spawn.test.ts @@ -12,6 +12,7 @@ import * as heartbeatWake from "../infra/heartbeat-wake.js"; import { __testing as sessionBindingServiceTesting, registerSessionBindingAdapter, + type SessionBindingPlacement, type SessionBindingRecord, } from "../infra/outbound/session-binding-service.js"; import * as acpSpawnParentStream from "./acp-spawn-parent-stream.js"; @@ -104,7 +105,7 @@ function createSessionBindingCapabilities() { adapterAvailable: true, bindSupported: true, unbindSupported: true, - placements: ["current", "child"] as const, + placements: ["current", "child"] satisfies SessionBindingPlacement[], }; } @@ -179,8 +180,8 @@ describe("spawnAcpDirect", () => { metaCleared: false, }); getAcpSessionManagerSpy.mockReset().mockReturnValue({ - initializeSession: async (params) => await hoisted.initializeSessionMock(params), - closeSession: async (params) => await hoisted.closeSessionMock(params), + initializeSession: async (params: unknown) => await hoisted.initializeSessionMock(params), + closeSession: async (params: unknown) => await hoisted.closeSessionMock(params), } as unknown as ReturnType); hoisted.initializeSessionMock.mockReset().mockImplementation(async (argsUnknown: unknown) => { const args = argsUnknown as { @@ -1039,7 +1040,7 @@ describe("spawnAcpDirect", () => { ...hoisted.state.cfg.channels, telegram: { threadBindings: { - spawnAcpSessions: true, + enabled: true, }, }, }, diff --git a/src/agents/subagent-announce.format.e2e.test.ts b/src/agents/subagent-announce.format.e2e.test.ts index 7e83742b5ce..280172dc073 100644 --- a/src/agents/subagent-announce.format.e2e.test.ts +++ b/src/agents/subagent-announce.format.e2e.test.ts @@ -68,8 +68,8 @@ const readLatestAssistantReplyMock = vi.fn( const embeddedRunMock = { isEmbeddedPiRunActive: vi.fn(() => false), isEmbeddedPiRunStreaming: vi.fn(() => false), - queueEmbeddedPiMessage: vi.fn(() => false), - waitForEmbeddedPiRunEnd: vi.fn(async () => true), + queueEmbeddedPiMessage: vi.fn((_: string, __: string) => false), + waitForEmbeddedPiRunEnd: vi.fn(async (_: string, __?: number) => true), }; const { subagentRegistryMock } = vi.hoisted(() => ({ subagentRegistryMock: { @@ -131,11 +131,17 @@ function setConfigOverride(next: OpenClawConfig): void { setRuntimeConfigSnapshot(configOverride); } -function loadSessionStoreFixture(): Record> { - return new Proxy(sessionStore, { +function loadSessionStoreFixture(): ReturnType { + return new Proxy(sessionStore as ReturnType, { get(target, key: string | symbol) { if (typeof key === "string" && !(key in target) && key.includes(":subagent:")) { - return { inputTokens: 1, outputTokens: 1, totalTokens: 2 }; + return { + sessionId: key, + updatedAt: Date.now(), + inputTokens: 1, + outputTokens: 1, + totalTokens: 2, + }; } return target[key as keyof typeof target]; }, @@ -207,7 +213,11 @@ describe("subagent announce formatting", () => { resolveAgentIdFromSessionKeySpy.mockReset().mockImplementation(() => "main"); resolveStorePathSpy.mockReset().mockImplementation(() => "/tmp/sessions.json"); resolveMainSessionKeySpy.mockReset().mockImplementation(() => "agent:main:main"); - getGlobalHookRunnerSpy.mockReset().mockImplementation(() => hookRunnerMock); + getGlobalHookRunnerSpy + .mockReset() + .mockImplementation( + () => hookRunnerMock as unknown as ReturnType, + ); readLatestAssistantReplySpy .mockReset() .mockImplementation(async (params) => await readLatestAssistantReplyMock(params?.sessionKey)); diff --git a/src/channels/plugins/message-action-names.ts b/src/channels/plugins/message-action-names.ts index aadff95c77d..3bf58083d14 100644 --- a/src/channels/plugins/message-action-names.ts +++ b/src/channels/plugins/message-action-names.ts @@ -51,6 +51,7 @@ export const CHANNEL_MESSAGE_ACTION_NAMES = [ "timeout", "kick", "ban", + "set-profile", "set-presence", "download-file", ] as const; diff --git a/src/commands/channels/add.ts b/src/commands/channels/add.ts index 03aa841edd5..ddddae5ee71 100644 --- a/src/commands/channels/add.ts +++ b/src/commands/channels/add.ts @@ -350,14 +350,15 @@ export async function channelsAddCommand( await writeConfigFile(nextConfig); runtime.log(`Added ${channelLabel(channel)} account "${accountId}".`); - if (plugin.setup.afterAccountConfigWritten) { + const setup = plugin.setup; + if (setup?.afterAccountConfigWritten) { await runCollectedChannelOnboardingPostWriteHooks({ hooks: [ { channel, accountId, run: async ({ cfg: writtenCfg, runtime: hookRuntime }) => - await plugin.setup.afterAccountConfigWritten?.({ + await setup.afterAccountConfigWritten?.({ previousCfg: cfg, cfg: writtenCfg, accountId, diff --git a/src/infra/matrix-plugin-helper.test.ts b/src/infra/matrix-plugin-helper.test.ts index 650edc434ca..ae71aca0bc8 100644 --- a/src/infra/matrix-plugin-helper.test.ts +++ b/src/infra/matrix-plugin-helper.test.ts @@ -2,6 +2,7 @@ import fs from "node:fs"; import path from "node:path"; import { describe, expect, it } from "vitest"; import { withTempHome } from "../../test/helpers/temp-home.js"; +import type { OpenClawConfig } from "../config/config.js"; import { isMatrixLegacyCryptoInspectorAvailable, loadMatrixLegacyCryptoInspector, @@ -89,13 +90,13 @@ describe("matrix plugin helper resolution", () => { ].join("\n"), ); - const cfg = { + const cfg: OpenClawConfig = { plugins: { load: { paths: [customRoot], }, }, - } as const; + }; expect(isMatrixLegacyCryptoInspectorAvailable({ cfg, env: process.env })).toBe(true); const inspectLegacyStore = await loadMatrixLegacyCryptoInspector({ @@ -160,13 +161,13 @@ describe("matrix plugin helper resolution", () => { return; } - const cfg = { + const cfg: OpenClawConfig = { plugins: { load: { paths: [customRoot], }, }, - } as const; + }; expect(isMatrixLegacyCryptoInspectorAvailable({ cfg, env: process.env })).toBe(false); await expect( diff --git a/src/infra/outbound/message-action-spec.ts b/src/infra/outbound/message-action-spec.ts index a71bc35b6fb..f5149e715ef 100644 --- a/src/infra/outbound/message-action-spec.ts +++ b/src/infra/outbound/message-action-spec.ts @@ -56,6 +56,7 @@ export const MESSAGE_ACTION_TARGET_MODE: Record