Matrix: fix typecheck and boundary drift
This commit is contained in:
parent
c4a4050ce4
commit
f69450b170
@ -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<string, unknown> } | 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([]);
|
||||
});
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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<ResolvedMatrixAccount> = {
|
||||
id: "matrix",
|
||||
meta,
|
||||
setupWizard: matrixSetupWizard,
|
||||
pairing: createTextPairingAdapter({
|
||||
idLabel: "matrixUserId",
|
||||
message: PAIRING_APPROVED_MESSAGE,
|
||||
|
||||
@ -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({
|
||||
|
||||
@ -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: [
|
||||
|
||||
@ -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;
|
||||
|
||||
1
extensions/matrix/src/matrix/index.ts
Normal file
1
extensions/matrix/src/matrix/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { monitorMatrixProvider } from "./monitor/index.js";
|
||||
@ -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");
|
||||
|
||||
@ -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),
|
||||
},
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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),
|
||||
},
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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";
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
},
|
||||
|
||||
@ -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<Record<typeof channel, string>>;
|
||||
|
||||
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<MatrixOnboardingStatus>;
|
||||
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> | 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;
|
||||
|
||||
@ -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<typeof acpSessionManager.getAcpSessionManager>);
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -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<string, Record<string, unknown>> {
|
||||
return new Proxy(sessionStore, {
|
||||
function loadSessionStoreFixture(): ReturnType<typeof configSessions.loadSessionStore> {
|
||||
return new Proxy(sessionStore as ReturnType<typeof configSessions.loadSessionStore>, {
|
||||
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<typeof hookRunnerGlobal.getGlobalHookRunner>,
|
||||
);
|
||||
readLatestAssistantReplySpy
|
||||
.mockReset()
|
||||
.mockImplementation(async (params) => await readLatestAssistantReplyMock(params?.sessionKey));
|
||||
|
||||
@ -51,6 +51,7 @@ export const CHANNEL_MESSAGE_ACTION_NAMES = [
|
||||
"timeout",
|
||||
"kick",
|
||||
"ban",
|
||||
"set-profile",
|
||||
"set-presence",
|
||||
"download-file",
|
||||
] as const;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -56,6 +56,7 @@ export const MESSAGE_ACTION_TARGET_MODE: Record<ChannelMessageActionName, Messag
|
||||
timeout: "none",
|
||||
kick: "none",
|
||||
ban: "none",
|
||||
"set-profile": "none",
|
||||
"set-presence": "none",
|
||||
"download-file": "none",
|
||||
};
|
||||
|
||||
8
test/helpers/extensions/matrix-route-test.ts
Normal file
8
test/helpers/extensions/matrix-route-test.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export type { OpenClawConfig } from "../../../src/config/config.js";
|
||||
export {
|
||||
__testing as sessionBindingTesting,
|
||||
registerSessionBindingAdapter,
|
||||
} from "../../../src/infra/outbound/session-binding-service.js";
|
||||
export { setActivePluginRegistry } from "../../../src/plugins/runtime.js";
|
||||
export { resolveAgentRoute } from "../../../src/routing/resolve-route.js";
|
||||
export { createTestRegistry } from "../../../src/test-utils/channel-plugins.js";
|
||||
Loading…
x
Reference in New Issue
Block a user