diff --git a/src/infra/matrix-migration-config.test.ts b/src/infra/matrix-migration-config.test.ts index bedf21d9d49..e2e82291b31 100644 --- a/src/infra/matrix-migration-config.test.ts +++ b/src/infra/matrix-migration-config.test.ts @@ -137,6 +137,50 @@ describe("resolveMatrixMigrationAccountTarget", () => { }); }); + it("does not inherit the base userId for non-default token-only accounts", async () => { + await withTempHome(async (home) => { + const stateDir = path.join(home, ".openclaw"); + writeFile( + path.join(stateDir, "credentials", "matrix", "credentials-ops.json"), + JSON.stringify( + { + homeserver: "https://matrix.example.org", + userId: "@ops-bot:example.org", + accessToken: "tok-ops", + deviceId: "DEVICE-OPS", + }, + null, + 2, + ), + ); + + const cfg: OpenClawConfig = { + channels: { + matrix: { + homeserver: "https://matrix.example.org", + userId: "@base-bot:example.org", + accounts: { + ops: { + homeserver: "https://matrix.example.org", + accessToken: "tok-ops", + }, + }, + }, + }, + }; + + const target = resolveMatrixMigrationAccountTarget({ + cfg, + env: process.env, + accountId: "ops", + }); + + expect(target).not.toBeNull(); + expect(target?.userId).toBe("@ops-bot:example.org"); + expect(target?.storedDeviceId).toBe("DEVICE-OPS"); + }); + }); + it("uses the same scoped env token encoding as runtime account auth", async () => { await withTempHome(async () => { const cfg: OpenClawConfig = { diff --git a/src/infra/matrix-migration-config.ts b/src/infra/matrix-migration-config.ts index 31753a3ccea..1fa7e1cdbe1 100644 --- a/src/infra/matrix-migration-config.ts +++ b/src/infra/matrix-migration-config.ts @@ -103,6 +103,11 @@ export function resolveMatrixMigrationConfigFields(params: { const account = resolveMatrixAccountConfigEntry(params.cfg, params.accountId); const scopedEnv = resolveScopedMatrixEnvConfig(params.accountId, params.env); const globalEnv = resolveGlobalMatrixEnvConfig(params.env); + const normalizedAccountId = normalizeAccountId(params.accountId); + const userId = + clean(account?.userId) || + scopedEnv.userId || + (normalizedAccountId === DEFAULT_ACCOUNT_ID ? clean(channel?.userId) || globalEnv.userId : ""); return { homeserver: @@ -110,8 +115,7 @@ export function resolveMatrixMigrationConfigFields(params: { scopedEnv.homeserver || clean(channel?.homeserver) || globalEnv.homeserver, - userId: - clean(account?.userId) || scopedEnv.userId || clean(channel?.userId) || globalEnv.userId, + userId, accessToken: clean(account?.accessToken) || scopedEnv.accessToken ||