diff --git a/src/app/features/bots/room.ts b/src/app/features/bots/room.ts index 3ade62eb..5a2636ed 100644 --- a/src/app/features/bots/room.ts +++ b/src/app/features/bots/room.ts @@ -37,18 +37,25 @@ export const isBotControlRoom = (mx: MatrixClient, room: Room, preset: BotPreset if (!ACTIVE_MEMBERSHIPS.has(myMembership)) return false; const botMember = room.getMember(preset.mxid); - if (!botMember) return false; + if ( + !botMember || + botMember.membership === undefined || + !ACTIVE_MEMBERSHIPS.has(botMember.membership) + ) { + return false; + } - const allowedMembers = new Set([myUserId, preset.mxid]); - const activeMembers = room - .getMembers() - .filter( - (member) => member.membership !== undefined && ACTIVE_MEMBERSHIPS.has(member.membership) - ); - - return ( - activeMembers.length > 0 && activeMembers.every((member) => allowedMembers.has(member.userId)) - ); + // A control DM is exactly the two of us, nobody else. Decide that from the room + // SUMMARY counts — NOT room.getMembers(): under Matrix lazy member-loading + // getMembers() returns only the members synced so far (heroes + recent senders + // + me), so a larger group whose loaded subset happens to be {me, bot} gets + // misclassified as the control DM. That bites a chat which began as a 1:1 with + // the bot (and still carries the sticky m.direct tag) but later gained people: + // it would wrongly drop out of the Direct tab (useDirectRooms excludes control + // DMs) and resurface only as a bot DM. getJoinedMemberCount()/ + // getInvitedMemberCount() come from the sync summary and stay accurate without + // loading every member — the same source useAutoDirectSync trusts for its 1:1 test. + return room.getJoinedMemberCount() + room.getInvitedMemberCount() === 2; }; export const isCatalogBotControlRoom = ( diff --git a/src/app/features/room/RoomViewHeaderDm.tsx b/src/app/features/room/RoomViewHeaderDm.tsx index 2e6d196f..0bc03600 100644 --- a/src/app/features/room/RoomViewHeaderDm.tsx +++ b/src/app/features/room/RoomViewHeaderDm.tsx @@ -288,7 +288,7 @@ const RoomMenu = forwardRef( {t('Room.pinned_messages')} - {canInvite && ( + {canInvite && !botControlRoom && (