/** * Team utility helpers * * Shared, dependency-free helpers operating on the `Team` / `TeamMember` * shape. Every module that needs to know who leads a team asks here — the * one rule (specs/2026-09-30-team-lead-rule.md): * * 1. the team's explicit `leaderIds` (or the deprecated `leaderId`), when * at least one of them is still a member; * 2. otherwise every member whose role is in * {@link TEAM_LEAD_CONSTANTS.LEAD_ROLES} (`team-leader`, `tech-lead`). * * `canDelegate` is NOT part of the rule. It stays a separate "delegation * authority" flag for the hierarchy (sub-leads with subordinates) and is the * last-resort routing fallback of {@link pickTeamLead}. A rule lead always * counts as able to delegate (see {@link canMemberDelegate}). * * @module utils/team.utils */ import { TEAM_LEAD_CONSTANTS } from '../constants.js'; import type { Team, TeamMember } from '../types/index.js'; /** The team fields the lead rule reads. */ export type TeamLeadSource = { members?: Array>; leaderIds?: string[]; leaderId?: string; }; /** How {@link setTeamLead} changes the leads. */ export type SetTeamLeadMode = (typeof TEAM_LEAD_CONSTANTS.SET_LEAD_MODES)[number]; /** * Whether a role is a lead role (used only when the team names no lead). * * @param role - Member role * @returns True for `team-leader` / `tech-lead` */ export declare function isLeadRole(role: string | undefined | null): boolean; /** * The ids of the members who lead a team — THE lead rule. * * @param team - Team * @returns Lead member ids (explicit ones, else lead-role members); empty when the team has no lead * * @example * ```typescript * getTeamLeadIds({ members: [{ id: 'o', role: 'tech-lead' }, { id: 'n', role: 'developer' }] }); // ['o'] * getTeamLeadIds({ leaderIds: ['n'], members: [...] }); // ['n'] * ``` */ export declare function getTeamLeadIds(team: TeamLeadSource): string[]; /** * Whether a member leads its team (see {@link getTeamLeadIds}). * * @param team - The member's team * @param member - The member * @returns True for a team lead */ export declare function isTeamLead(team: TeamLeadSource, member: Pick): boolean; /** * The lead members of a team, in rule order. * * @param team - Team * @returns Lead members (may be empty) */ export declare function getTeamLeads(team: Team): TeamMember[]; /** * Whether a member may delegate: a team lead by the rule, or a member the * hierarchy flagged with `canDelegate` (a sub-lead of its subordinates). * This is what lead-only prompt modules (TL addon, TL soul overlay, TL * skills) and delegation checks key on, so a lead set by the rule gets them * on its next wake without a separate flag. * * @param team - The member's team * @param member - The member * @returns True when the member may delegate */ export declare function canMemberDelegate(team: TeamLeadSource, member: Pick): boolean; /** * The members a delegating member directs: its `subordinateIds` (or the * members naming it as parent); for a rule lead with neither, every other * member that is not itself a lead and reports to nobody else. * * @param team - The member's team * @param member - The member * @returns Subordinate members (may be empty) */ export declare function getLeadSubordinates(team: Team, member: TeamMember): TeamMember[]; /** * Choose the ONE member to route "the team lead" traffic to. * * Resolution (first match wins): * 1. A lead by the rule ({@link getTeamLeadIds}); among several, the one * the hierarchy marks as top (`hierarchyLevel === 1 && canDelegate`), * else the first. * 2. Legacy routing fallback — a member flagged `canDelegate` (hierarchy * data imported without `leaderIds` or a lead role). Not a lead by the * rule; kept so escalations of such teams still reach someone. * 3. First member — better to dispatch to _someone_ than silently drop a * `@team` ping. **Emits a warn-log (#332)**. * * Returns `null` only when the team has no members at all. * * @param team - The matched team. * @returns The member to dispatch to, or `null` when the team has no members. * * @example * ```typescript * const tl = pickTeamLead(team); * if (tl) await sendNotification({ to: tl.sessionName }); * ``` */ export declare function pickTeamLead(team: Team): TeamMember | null; /** * Store the lead rule's answer on the team (idempotent migration, run on * every load and save): a team with no usable explicit leads but with * lead-role members gets `leaderIds` = those members; `leaderId` always * mirrors `leaderIds[0]` for back-compat. The rule's answer never changes — * only where it is stored. Dangling explicit ids (members since removed) * are dropped when at least one explicit lead remains. * * @param team - Team (mutated) * @returns True when the team changed */ export declare function normalizeTeamLeaderIds(team: { members?: Array>; leaderIds?: string[]; leaderId?: string; }): boolean; /** * Make a member a lead of its team (`POST /api/teams/:id/lead`, the * `set-team-lead` skill, the dashboard "Make lead" toggle). * * - `set` (default): the member becomes THE lead. Former leads lose the * lead's delegation flag, and members that reported to a former lead now * report to the new one. * - `add`: the member joins the existing leads. * * The lead gets `canDelegate = true` (so the in-process delegation guard and * hierarchy views agree) and `hierarchyLevel = 1` on hierarchical teams. * * @param team - Team (mutated) * @param memberId - Member to make lead * @param mode - `set` or `add` * @returns The lead ids before and after * @throws Error when the member is not on the team or is the orchestrator */ export declare function setTeamLead(team: Team, memberId: string, mode?: SetTeamLeadMode): { before: string[]; after: string[]; changed: boolean; }; /** * The session of the lead who answers for a member: the first lead (with a * session) of the first team the member belongs to, other than the member. * * @param teams - All teams * @param session - The member's session name * @returns The lead's session name, or null when none is found */ export declare function findLeadSessionFor(teams: readonly Team[], session: string): string | null; //# sourceMappingURL=team.utils.d.ts.map