/ utils / teamDiscovery.ts
teamDiscovery.ts
 1  /**
 2   * Team Discovery - Utilities for discovering teams and teammate status
 3   *
 4   * Scans ~/.claude/teams/ to find teams where the current session is the leader.
 5   * Used by the Teams UI in the footer to show team status.
 6   */
 7  
 8  import { isPaneBackend, type PaneBackendType } from './swarm/backends/types.js'
 9  import { readTeamFile } from './swarm/teamHelpers.js'
10  
11  export type TeamSummary = {
12    name: string
13    memberCount: number
14    runningCount: number
15    idleCount: number
16  }
17  
18  export type TeammateStatus = {
19    name: string
20    agentId: string
21    agentType?: string
22    model?: string
23    prompt?: string
24    status: 'running' | 'idle' | 'unknown'
25    color?: string
26    idleSince?: string // ISO timestamp from idle notification
27    tmuxPaneId: string
28    cwd: string
29    worktreePath?: string
30    isHidden?: boolean // Whether the pane is currently hidden from the swarm view
31    backendType?: PaneBackendType // The backend type used for this teammate
32    mode?: string // Current permission mode for this teammate
33  }
34  
35  /**
36   * Get detailed teammate statuses for a team
37   * Reads isActive from config to determine status
38   */
39  export function getTeammateStatuses(teamName: string): TeammateStatus[] {
40    const teamFile = readTeamFile(teamName)
41    if (!teamFile) {
42      return []
43    }
44  
45    const hiddenPaneIds = new Set(teamFile.hiddenPaneIds ?? [])
46    const statuses: TeammateStatus[] = []
47  
48    for (const member of teamFile.members) {
49      // Exclude team-lead from the list
50      if (member.name === 'team-lead') {
51        continue
52      }
53  
54      // Read isActive from config, defaulting to true (active) if undefined
55      const isActive = member.isActive !== false
56      const status: 'running' | 'idle' = isActive ? 'running' : 'idle'
57  
58      statuses.push({
59        name: member.name,
60        agentId: member.agentId,
61        agentType: member.agentType,
62        model: member.model,
63        prompt: member.prompt,
64        status,
65        color: member.color,
66        tmuxPaneId: member.tmuxPaneId,
67        cwd: member.cwd,
68        worktreePath: member.worktreePath,
69        isHidden: hiddenPaneIds.has(member.tmuxPaneId),
70        backendType:
71          member.backendType && isPaneBackend(member.backendType)
72            ? member.backendType
73            : undefined,
74        mode: member.mode,
75      })
76    }
77  
78    return statuses
79  }
80  
81  // Note: For time formatting, use formatRelativeTimeAgo from '../utils/format.js'