/** * Groups card model (PR1) — pure projection of the dashboard groups matrix * (`/api/groups` fan-out, see `dashboard.ts:595-650`) into list-card and * detail-card DTOs. * * Zero IO. Self-contained input shape; no imports from `web/`, * `dashboard.ts`, or the registry. */ import type { ButtonState, PaginationMeta } from './card-model-types.js'; /** Possible coverage states for one (chat, bot) cell. */ export type GroupCoverageStatus = 'in' | 'out' | 'unknown' | 'error'; /** Oncall binding shape — mirrors `services/oncall-store.ts:28-35 OncallChat`. */ export interface GroupsOncallChatInput { chatId: string; workingDir: string; } /** Per-bot membership row inside a chat. Caller fans out across all configured bots. */ export interface GroupsMemberBotInput { larkAppId: string; botName: string; /** True/false from the daemon `/api/groups//membership`. Absent → status decides. */ inChat?: boolean; /** Oncall binding object when bound; null/undefined when not bound. * Following dashboard's contract (`web/groups.ts:440-451`), the mere presence of * the object marks "bound" — `workingDir` may be empty string and still indicates * an explicit bind. */ oncallChat?: GroupsOncallChatInput | null; /** Failure / unknown signal supplied by the aggregator (e.g. daemon offline → 'unknown'; fetch error → 'error'). */ status?: 'error' | 'unknown'; hasRole?: boolean; } /** One chat row (a Lark group / topic group / multi-user chat). */ export interface GroupsChatInput { chatId: string; name?: string; ownerId?: string; memberBots: GroupsMemberBotInput[]; } /** Configured bot metadata for the matrix column header order. */ export interface GroupsBotInput { larkAppId: string; botName: string; } export interface GroupsFilter { query?: string; /** When true, keep only chats where at least one configured bot is NOT in chat. */ missingOnly?: boolean; } /** Single (chat, bot) matrix cell. */ export interface CoverageCell { larkAppId: string; botName: string; status: GroupCoverageStatus; } export interface GroupRowDto { chatId: string; /** Last `chatIdLen` (default 4) chars of `chatId`, for compact display. */ chatIdSuffix: string; name: string; ownerId?: string; /** Coverage cells in `bots` argument order. */ coverage: CoverageCell[]; /** Number of cells whose status !== 'in'. */ missingCount: number; totalBots: number; } export interface GroupDetailMemberDto { larkAppId: string; botName: string; status: GroupCoverageStatus; /** True when this bot is the owner of the chat (ownerId === larkAppId). */ isOwnerBot: boolean; /** Raw oncall binding passthrough; null when unbound. */ oncallChat: GroupsOncallChatInput | null; /** Convenience projection of `oncallChat.workingDir` (or null when unbound). */ oncallWorkingDir: string | null; /** True when this bot has a per-chat role description configured. */ hasRole: boolean; /** bind action button availability. */ bind: ButtonState; /** unbind action button availability. */ unbind: ButtonState; } export interface GroupDetailDto { chatId: string; chatIdSuffix: string; name: string; ownerId?: string; members: GroupDetailMemberDto[]; } export interface GroupListPage { rows: GroupRowDto[]; meta: PaginationMeta; } /** Return the last `len` characters of a chatId (whole string when too short). */ export declare function chatIdSuffix(chatId: string, len?: number): string; /** * Filter groups by query / missingOnly. missingOnly keeps a chat when * at least one configured bot is NOT effectively covered — covers all four * gap types: inChat=false / member row absent / status='unknown' / status='error'. * * When the optional `bots` universe is provided, `missingOnly` also detects * chats whose memberBots list omits a configured bot entirely. Without `bots`, * it falls back to the three gap types observable from memberBots alone. */ export declare function filterGroups(chats: ReadonlyArray, filter: GroupsFilter, bots?: ReadonlyArray): GroupsChatInput[]; /** Slice a filtered group list into one page. Clamp rules apply. */ export declare function paginateGroups(chats: ReadonlyArray, page?: number, pageSize?: number): { total: number; page: number; pageSize: number; pageItems: GroupsChatInput[]; }; /** Build one matrix row DTO. Coverage column order follows the `bots` argument. */ export declare function buildGroupRow(chat: GroupsChatInput, bots: ReadonlyArray): GroupRowDto; /** Pipeline: filter → paginate → row-mapping. */ export declare function buildGroupRows(chats: ReadonlyArray, bots: ReadonlyArray, filter: GroupsFilter, page?: number, pageSize?: number): GroupListPage; /** Build the detail-card DTO including per-bot bind/unbind action availability. */ export declare function buildGroupDetail(chat: GroupsChatInput, bots: ReadonlyArray): GroupDetailDto; //# sourceMappingURL=groups-card-model.d.ts.map