AgentSkillsCN

pfTeamList

列出当前 PlanFlow 项目中的团队成员

SKILL.md
--- frontmatter
name: pfTeamList
description: List team members for the current PlanFlow project

PlanFlow Team List

Display team members, their roles, and current activity for the linked cloud project.

Usage

bash
/pfTeamList                 # List all team members

Step 0: Load Configuration

javascript
function getConfig() {
  const localConfigPath = "./.plan-config.json"
  let localConfig = {}
  if (fileExists(localConfigPath)) {
    try { localConfig = JSON.parse(readFile(localConfigPath)) } catch {}
  }

  const globalConfigPath = expandPath("~/.config/claude/plan-plugin-config.json")
  let globalConfig = {}
  if (fileExists(globalConfigPath)) {
    try { globalConfig = JSON.parse(readFile(globalConfigPath)) } catch {}
  }

  // Merge configs: local overrides global, cloud sections are merged
  return {
    ...globalConfig,
    ...localConfig,
    cloud: {
      ...(globalConfig.cloud || {}),
      ...(localConfig.cloud || {})
    }
  }
}

const config = getConfig()
const language = config.language || "en"
const cloudConfig = config.cloud || {}
const isAuthenticated = !!cloudConfig.apiToken
const projectId = cloudConfig.projectId
const apiUrl = cloudConfig.apiUrl || "https://api.planflow.tools"

const t = JSON.parse(readFile(`locales/${language}.json`))

Step 1: Validate Authentication

If not authenticated:

code
❌ {t.commands.sync.notAuthenticated}

Run: /pfLogin

Step 2: Validate Project Link

If no project is linked:

code
❌ {t.commands.sync.notLinked}

Run: /pfCloudLink <project-id>

Step 3: Fetch Team Members

API Call:

bash
curl -s \
  -H "Authorization: Bearer {TOKEN}" \
  -H "Accept: application/json" \
  "https://api.planflow.tools/projects/{PROJECT_ID}/team"

Expected Response:

json
{
  "success": true,
  "data": {
    "projectId": "uuid",
    "projectName": "My Project",
    "members": [
      {
        "id": "uuid",
        "email": "john@company.com",
        "name": "John Doe",
        "role": "owner",
        "status": "online",
        "currentTask": {
          "taskId": "T2.1",
          "name": "API endpoints"
        },
        "lastSeen": null
      },
      {
        "id": "uuid",
        "email": "jane@company.com",
        "name": "Jane Smith",
        "role": "admin",
        "status": "online",
        "currentTask": {
          "taskId": "T3.5",
          "name": "Dashboard"
        },
        "lastSeen": null
      },
      {
        "id": "uuid",
        "email": "bob@company.com",
        "name": "Bob Wilson",
        "role": "editor",
        "status": "offline",
        "currentTask": null,
        "lastSeen": "2026-02-01T10:30:00Z"
      }
    ],
    "pendingInvites": [
      {
        "email": "alice@company.com",
        "role": "editor",
        "invitedAt": "2026-02-01T09:00:00Z"
      }
    ]
  }
}

Step 4: Display Team Members

Pseudo-code:

javascript
function formatRole(role) {
  const roleMap = {
    "owner": "Owner",
    "admin": "Admin",
    "editor": "Editor",
    "viewer": "Viewer"
  }
  return roleMap[role] || role
}

function formatStatus(member) {
  if (member.status === "online") {
    return "🟢"
  }
  return "🔴"
}

function formatLastSeen(timestamp) {
  if (!timestamp) return ""
  const now = new Date()
  const then = new Date(timestamp)
  const diffMinutes = Math.floor((now - then) / 60000)

  if (diffMinutes < 60) {
    return `${diffMinutes} min ago`
  }
  const diffHours = Math.floor(diffMinutes / 60)
  if (diffHours < 24) {
    return `${diffHours} hour${diffHours > 1 ? 's' : ''} ago`
  }
  const diffDays = Math.floor(diffHours / 24)
  return `${diffDays} day${diffDays > 1 ? 's' : ''} ago`
}

let output = ""
output += `👥 ${t.commands.team.title}\n\n`
output += `📁 Project: ${data.projectName}\n\n`

for (const member of data.members) {
  const statusIcon = formatStatus(member)
  const role = formatRole(member.role)

  output += `  ${statusIcon} ${member.name} (${role})`
  output += `      ${member.email}\n`

  if (member.status === "online" && member.currentTask) {
    output += `     ${t.commands.team.workingOn}: ${member.currentTask.taskId} - ${member.currentTask.name}\n`
  } else if (member.status === "offline") {
    output += `     ${t.commands.team.lastSeen}: ${formatLastSeen(member.lastSeen)}\n`
  }
  output += "\n"
}

// Show pending invites if any
if (data.pendingInvites && data.pendingInvites.length > 0) {
  output += `\n📨 ${t.commands.team.pendingInvites} (${data.pendingInvites.length})\n`
  for (const invite of data.pendingInvites) {
    output += `  ⏳ ${invite.email} (${formatRole(invite.role)})\n`
  }
}

output += "\n"
output += `💡 ${t.commands.team.commands}:\n`
output += `  /pfTeamInvite <email>        ${t.commands.team.inviteHint}\n`
output += `  /pfTeamRole <email> <role>   ${t.commands.team.roleHint}\n`
output += `  /pfTeamRemove <email>        ${t.commands.team.removeHint}\n`

Example Output:

code
👥 Team Members

📁 Project: Planflow Plugin

  🟢 John Doe (Owner)      john@company.com
     Working on: T2.1 - API endpoints

  🟢 Jane Smith (Admin)    jane@company.com
     Working on: T3.5 - Dashboard

  🔴 Bob Wilson (Editor)   bob@company.com
     Last seen: 2 hours ago

📨 Pending Invites (1)
  ⏳ alice@company.com (Editor)

💡 Commands:
  /pfTeamInvite <email>        Invite a team member
  /pfTeamRole <email> <role>   Change member role
  /pfTeamRemove <email>        Remove from team

Georgian Example Output:

code
👥 გუნდის წევრები

📁 პროექტი: Planflow Plugin

  🟢 John Doe (მფლობელი)      john@company.com
     მუშაობს: T2.1 - API endpoints

  🟢 Jane Smith (ადმინი)    jane@company.com
     მუშაობს: T3.5 - Dashboard

  🔴 Bob Wilson (რედაქტორი)   bob@company.com
     ბოლოს ნანახი: 2 საათის წინ

📨 მოლოდინში მყოფი მოწვევები (1)
  ⏳ alice@company.com (რედაქტორი)

💡 ბრძანებები:
  /pfTeamInvite <email>        მოიწვიე გუნდის წევრი
  /pfTeamRole <email> <role>   შეცვალე წევრის როლი
  /pfTeamRemove <email>        წაშალე გუნდიდან

Step 5: Handle Empty Team

If only the owner exists (no team members):

code
👥 Team Members

📁 Project: Planflow Plugin

  🟢 You (Owner)      your@email.com

ℹ️ You're the only team member.

💡 To invite collaborators:
  /pfTeamInvite <email>
  /pfTeamInvite <email> admin    (with role)

Error Handling

Network Error:

code
❌ Network error. Could not fetch team information.

Please check your connection and try again.

API Error (401 Unauthorized):

code
❌ Authentication failed. Your session may have expired.

Run: /pfLogin

API Error (403 Forbidden):

code
❌ You don't have permission to view team members.

Only project members can view the team list.

API Error (404 Not Found):

code
❌ Project not found on cloud.

The linked project may have been deleted.
Run: /pfCloudList to see available projects.

Translation Keys Required

Add these to locales/en.json and locales/ka.json:

English:

json
{
  "commands": {
    "team": {
      "title": "Team Members",
      "project": "Project",
      "workingOn": "Working on",
      "lastSeen": "Last seen",
      "pendingInvites": "Pending Invites",
      "commands": "Commands",
      "inviteHint": "Invite a team member",
      "roleHint": "Change member role",
      "removeHint": "Remove from team",
      "onlyYou": "You're the only team member.",
      "invitePrompt": "To invite collaborators:",
      "noPermission": "You don't have permission to view team members.",
      "projectNotFound": "Project not found on cloud.",
      "roles": {
        "owner": "Owner",
        "admin": "Admin",
        "editor": "Editor",
        "viewer": "Viewer"
      }
    }
  }
}

Georgian:

json
{
  "commands": {
    "team": {
      "title": "გუნდის წევრები",
      "project": "პროექტი",
      "workingOn": "მუშაობს",
      "lastSeen": "ბოლოს ნანახი",
      "pendingInvites": "მოლოდინში მყოფი მოწვევები",
      "commands": "ბრძანებები",
      "inviteHint": "მოიწვიე გუნდის წევრი",
      "roleHint": "შეცვალე წევრის როლი",
      "removeHint": "წაშალე გუნდიდან",
      "onlyYou": "შენ ხარ ერთადერთი გუნდის წევრი.",
      "invitePrompt": "კოლაბორატორების მოსაწვევად:",
      "noPermission": "შენ არ გაქვს უფლება გუნდის წევრების სანახავად.",
      "projectNotFound": "პროექტი ვერ მოიძებნა ქლაუდში.",
      "roles": {
        "owner": "მფლობელი",
        "admin": "ადმინი",
        "editor": "რედაქტორი",
        "viewer": "მაყურებელი"
      }
    }
  }
}

Bash Implementation

Full Implementation:

bash
#!/bin/bash

# Load config
API_URL="https://api.planflow.tools"
TOKEN="$API_TOKEN"
PROJECT_ID="$PROJECT_ID"

# Fetch team members
RESPONSE=$(curl -s -w "\n%{http_code}" \
  --connect-timeout 5 \
  --max-time 10 \
  -X GET \
  -H "Accept: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  "${API_URL}/projects/${PROJECT_ID}/team")

HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')

if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
  echo "👥 Team Members"
  echo ""
  # Parse and display (Claude will format the JSON response)
else
  echo "❌ Failed to fetch team (HTTP $HTTP_CODE)"
fi

Notes

  • This command requires the project to be linked to a cloud project
  • Team member statuses are real-time when the platform supports WebSocket connections
  • The "Working on" field shows the task the member is currently assigned to with IN_PROGRESS status
  • Pending invites are shown separately from active members