planflow-plugin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +93 -0
- package/bin/cli.js +169 -0
- package/bin/postinstall.js +87 -0
- package/commands/pfActivity/SKILL.md +725 -0
- package/commands/pfAssign/SKILL.md +623 -0
- package/commands/pfCloudLink/SKILL.md +192 -0
- package/commands/pfCloudList/SKILL.md +222 -0
- package/commands/pfCloudNew/SKILL.md +187 -0
- package/commands/pfCloudUnlink/SKILL.md +152 -0
- package/commands/pfComment/SKILL.md +227 -0
- package/commands/pfComments/SKILL.md +159 -0
- package/commands/pfConnectionStatus/SKILL.md +433 -0
- package/commands/pfDiscord/SKILL.md +740 -0
- package/commands/pfGithubBranch/SKILL.md +672 -0
- package/commands/pfGithubIssue/SKILL.md +963 -0
- package/commands/pfGithubLink/SKILL.md +859 -0
- package/commands/pfGithubPr/SKILL.md +1335 -0
- package/commands/pfGithubUnlink/SKILL.md +401 -0
- package/commands/pfLive/SKILL.md +185 -0
- package/commands/pfLogin/SKILL.md +249 -0
- package/commands/pfLogout/SKILL.md +155 -0
- package/commands/pfMyTasks/SKILL.md +198 -0
- package/commands/pfNotificationSettings/SKILL.md +619 -0
- package/commands/pfNotifications/SKILL.md +420 -0
- package/commands/pfNotificationsClear/SKILL.md +421 -0
- package/commands/pfReact/SKILL.md +232 -0
- package/commands/pfSlack/SKILL.md +659 -0
- package/commands/pfSyncPull/SKILL.md +210 -0
- package/commands/pfSyncPush/SKILL.md +299 -0
- package/commands/pfSyncStatus/SKILL.md +212 -0
- package/commands/pfTeamInvite/SKILL.md +161 -0
- package/commands/pfTeamList/SKILL.md +253 -0
- package/commands/pfTeamRemove/SKILL.md +115 -0
- package/commands/pfTeamRole/SKILL.md +160 -0
- package/commands/pfTestWebhooks/SKILL.md +722 -0
- package/commands/pfUnassign/SKILL.md +134 -0
- package/commands/pfWhoami/SKILL.md +258 -0
- package/commands/pfWorkload/SKILL.md +219 -0
- package/commands/planExportCsv/SKILL.md +106 -0
- package/commands/planExportGithub/SKILL.md +222 -0
- package/commands/planExportJson/SKILL.md +159 -0
- package/commands/planExportSummary/SKILL.md +158 -0
- package/commands/planNew/SKILL.md +641 -0
- package/commands/planNext/SKILL.md +1200 -0
- package/commands/planSettingsAutoSync/SKILL.md +199 -0
- package/commands/planSettingsLanguage/SKILL.md +201 -0
- package/commands/planSettingsReset/SKILL.md +237 -0
- package/commands/planSettingsShow/SKILL.md +482 -0
- package/commands/planSpec/SKILL.md +929 -0
- package/commands/planUpdate/SKILL.md +2518 -0
- package/commands/team/SKILL.md +740 -0
- package/locales/en.json +1499 -0
- package/locales/ka.json +1499 -0
- package/package.json +48 -0
- package/templates/PROJECT_PLAN.template.md +157 -0
- package/templates/backend-api.template.md +562 -0
- package/templates/frontend-spa.template.md +610 -0
- package/templates/fullstack.template.md +397 -0
- package/templates/ka/backend-api.template.md +562 -0
- package/templates/ka/frontend-spa.template.md +610 -0
- package/templates/ka/fullstack.template.md +397 -0
- package/templates/sections/architecture.md +21 -0
- package/templates/sections/overview.md +15 -0
- package/templates/sections/tasks.md +22 -0
- package/templates/sections/tech-stack.md +19 -0
|
@@ -0,0 +1,740 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: team
|
|
3
|
+
description: View and manage team members for the current PlanFlow project
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Team Management
|
|
7
|
+
|
|
8
|
+
A unified command for viewing team members, inviting new members, and managing roles in the linked cloud project.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
/team # List all team members
|
|
14
|
+
/team add <email> # Invite with default role (editor)
|
|
15
|
+
/team add <email> <role> # Invite with specific role
|
|
16
|
+
/team role <email> <role> # Change member's role
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Available Roles
|
|
20
|
+
|
|
21
|
+
| Role | Permissions |
|
|
22
|
+
|------|-------------|
|
|
23
|
+
| `admin` | Full access, can manage team members |
|
|
24
|
+
| `editor` | Can edit tasks and plan (default) |
|
|
25
|
+
| `viewer` | Read-only access |
|
|
26
|
+
|
|
27
|
+
## Step 0: Load Configuration
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
function getConfig() {
|
|
31
|
+
const localConfigPath = "./.plan-config.json"
|
|
32
|
+
let localConfig = {}
|
|
33
|
+
if (fileExists(localConfigPath)) {
|
|
34
|
+
try { localConfig = JSON.parse(readFile(localConfigPath)) } catch {}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const globalConfigPath = expandPath("~/.config/claude/plan-plugin-config.json")
|
|
38
|
+
let globalConfig = {}
|
|
39
|
+
if (fileExists(globalConfigPath)) {
|
|
40
|
+
try { globalConfig = JSON.parse(readFile(globalConfigPath)) } catch {}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
...globalConfig,
|
|
45
|
+
...localConfig,
|
|
46
|
+
cloud: {
|
|
47
|
+
...(globalConfig.cloud || {}),
|
|
48
|
+
...(localConfig.cloud || {})
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const config = getConfig()
|
|
54
|
+
const language = config.language || "en"
|
|
55
|
+
const cloudConfig = config.cloud || {}
|
|
56
|
+
const isAuthenticated = !!cloudConfig.apiToken
|
|
57
|
+
const projectId = cloudConfig.projectId
|
|
58
|
+
const apiUrl = cloudConfig.apiUrl || "https://api.planflow.tools"
|
|
59
|
+
|
|
60
|
+
const t = JSON.parse(readFile(`locales/${language}.json`))
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Step 0.5: Show Notification Badge (v1.6.0+)
|
|
64
|
+
|
|
65
|
+
**Purpose:** Display unread notification count to keep users informed of team activity.
|
|
66
|
+
|
|
67
|
+
**When to Execute:** Only if authenticated AND linked to a project.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Only proceed if authenticated and linked
|
|
71
|
+
if [ -n "$TOKEN" ] && [ -n "$PROJECT_ID" ]; then
|
|
72
|
+
RESPONSE=$(curl -s --connect-timeout 3 --max-time 5 \
|
|
73
|
+
-X GET \
|
|
74
|
+
-H "Accept: application/json" \
|
|
75
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
76
|
+
"${API_URL}/projects/${PROJECT_ID}/notifications?limit=1&unread=true" 2>/dev/null)
|
|
77
|
+
|
|
78
|
+
if [ $? -eq 0 ]; then
|
|
79
|
+
UNREAD_COUNT=$(echo "$RESPONSE" | grep -o '"unreadCount":[0-9]*' | grep -o '[0-9]*')
|
|
80
|
+
if [ -n "$UNREAD_COUNT" ] && [ "$UNREAD_COUNT" -gt 0 ]; then
|
|
81
|
+
echo "🔔 $UNREAD_COUNT unread notification(s) — /pfNotifications to view"
|
|
82
|
+
echo ""
|
|
83
|
+
fi
|
|
84
|
+
fi
|
|
85
|
+
fi
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
See: `skills/notification-badge/SKILL.md` for full implementation details.
|
|
89
|
+
|
|
90
|
+
## Step 1: Validate Authentication
|
|
91
|
+
|
|
92
|
+
If not authenticated, display error card:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
96
|
+
│ ❌ ERROR │
|
|
97
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
98
|
+
│ │
|
|
99
|
+
│ {t.commands.sync.notAuthenticated} │
|
|
100
|
+
│ │
|
|
101
|
+
│ 💡 {t.ui.labels.nextSteps} │
|
|
102
|
+
│ • /pfLogin Sign in to PlanFlow │
|
|
103
|
+
│ │
|
|
104
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Step 2: Validate Project Link
|
|
108
|
+
|
|
109
|
+
If no project is linked, display error card:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
113
|
+
│ ❌ ERROR │
|
|
114
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
115
|
+
│ │
|
|
116
|
+
│ {t.commands.sync.notLinked} │
|
|
117
|
+
│ │
|
|
118
|
+
│ 💡 {t.ui.labels.nextSteps} │
|
|
119
|
+
│ • /pfCloudLink Link to a cloud project │
|
|
120
|
+
│ │
|
|
121
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Step 3: Parse Arguments
|
|
125
|
+
|
|
126
|
+
Parse the command arguments to determine the subcommand:
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
const args = commandArgs.trim()
|
|
130
|
+
const parts = args.split(/\s+/)
|
|
131
|
+
|
|
132
|
+
// Determine action
|
|
133
|
+
let action = "list" // default
|
|
134
|
+
let email = null
|
|
135
|
+
let role = null
|
|
136
|
+
|
|
137
|
+
if (parts.length === 0 || parts[0] === "" || parts[0] === "list") {
|
|
138
|
+
action = "list"
|
|
139
|
+
} else if (parts[0] === "add") {
|
|
140
|
+
action = "add"
|
|
141
|
+
email = parts[1]
|
|
142
|
+
role = parts[2] || "editor"
|
|
143
|
+
} else if (parts[0] === "role") {
|
|
144
|
+
action = "role"
|
|
145
|
+
email = parts[1]
|
|
146
|
+
role = parts[2]
|
|
147
|
+
} else {
|
|
148
|
+
// Unknown subcommand - show usage
|
|
149
|
+
action = "usage"
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Step 4: Route to Action
|
|
154
|
+
|
|
155
|
+
Based on the parsed action, execute the appropriate flow.
|
|
156
|
+
|
|
157
|
+
### Action: usage (Unknown Command)
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
161
|
+
│ 👥 Team Management │
|
|
162
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
163
|
+
│ │
|
|
164
|
+
│ ── Usage ───────────────────────────────────────────────────────────────── │
|
|
165
|
+
│ │
|
|
166
|
+
│ /team List all team members │
|
|
167
|
+
│ /team add <email> Invite with default role (editor) │
|
|
168
|
+
│ /team add <email> <role> Invite with specific role │
|
|
169
|
+
│ /team role <email> <role> Change member's role │
|
|
170
|
+
│ │
|
|
171
|
+
│ ── Available Roles ─────────────────────────────────────────────────────── │
|
|
172
|
+
│ │
|
|
173
|
+
│ admin - Full access, can manage team members │
|
|
174
|
+
│ editor - Can edit tasks and plan (default) │
|
|
175
|
+
│ viewer - Read-only access │
|
|
176
|
+
│ │
|
|
177
|
+
│ ── Examples ────────────────────────────────────────────────────────────── │
|
|
178
|
+
│ │
|
|
179
|
+
│ /team │
|
|
180
|
+
│ /team add alice@company.com │
|
|
181
|
+
│ /team add bob@company.com admin │
|
|
182
|
+
│ /team role bob@company.com viewer │
|
|
183
|
+
│ │
|
|
184
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### Action: list (Default)
|
|
190
|
+
|
|
191
|
+
Fetch and display team members.
|
|
192
|
+
|
|
193
|
+
**API Call:**
|
|
194
|
+
```bash
|
|
195
|
+
curl -s \
|
|
196
|
+
-H "Authorization: Bearer {TOKEN}" \
|
|
197
|
+
-H "Accept: application/json" \
|
|
198
|
+
"https://api.planflow.tools/projects/{PROJECT_ID}/team"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Success Card:**
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
205
|
+
│ 👥 {t.commands.team.title} │
|
|
206
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
207
|
+
│ │
|
|
208
|
+
│ 📁 {t.commands.team.project}: {projectName} │
|
|
209
|
+
│ │
|
|
210
|
+
│ ── Active Members ({count}) ──────────────────────────────────────────── │
|
|
211
|
+
│ │
|
|
212
|
+
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
213
|
+
│ │ 🟢 John Doe ({t.commands.team.roles.owner}) │ │
|
|
214
|
+
│ │ john@company.com │ │
|
|
215
|
+
│ │ {t.commands.team.workingOn}: T2.1 - API endpoints │ │
|
|
216
|
+
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
217
|
+
│ │
|
|
218
|
+
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
219
|
+
│ │ 🟢 Jane Smith ({t.commands.team.roles.admin}) │ │
|
|
220
|
+
│ │ jane@company.com │ │
|
|
221
|
+
│ │ {t.commands.team.workingOn}: T3.5 - Dashboard │ │
|
|
222
|
+
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
223
|
+
│ │
|
|
224
|
+
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
225
|
+
│ │ 🔴 Bob Wilson ({t.commands.team.roles.editor}) │ │
|
|
226
|
+
│ │ bob@company.com │ │
|
|
227
|
+
│ │ {t.commands.team.lastSeen}: 2 hours ago │ │
|
|
228
|
+
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
229
|
+
│ │
|
|
230
|
+
│ ── {t.commands.team.pendingInvites} ({inviteCount}) ──────────────────── │
|
|
231
|
+
│ │
|
|
232
|
+
│ ⏳ alice@company.com (Editor) - sent 2 days ago │
|
|
233
|
+
│ │
|
|
234
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
235
|
+
│ │
|
|
236
|
+
│ 💡 {t.commands.team.commands} │
|
|
237
|
+
│ • /team add <email> {t.commands.team.inviteHint} │
|
|
238
|
+
│ • /team role <email> <role> {t.commands.team.roleHint} │
|
|
239
|
+
│ │
|
|
240
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
241
|
+
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Only Owner (Empty Team) Card:**
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
248
|
+
│ 👥 {t.commands.team.title} │
|
|
249
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
250
|
+
│ │
|
|
251
|
+
│ 📁 {t.commands.team.project}: {projectName} │
|
|
252
|
+
│ │
|
|
253
|
+
│ ── Active Members (1) ────────────────────────────────────────────────── │
|
|
254
|
+
│ │
|
|
255
|
+
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
256
|
+
│ │ 🟢 You ({t.commands.team.roles.owner}) │ │
|
|
257
|
+
│ │ your@email.com │ │
|
|
258
|
+
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
259
|
+
│ │
|
|
260
|
+
│ ℹ️ {t.commands.team.onlyYou} │
|
|
261
|
+
│ │
|
|
262
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
263
|
+
│ │
|
|
264
|
+
│ 💡 {t.commands.team.invitePrompt} │
|
|
265
|
+
│ • /team add <email> │
|
|
266
|
+
│ • /team add <email> admin (with role) │
|
|
267
|
+
│ │
|
|
268
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
### Action: add (Invite Team Member)
|
|
274
|
+
|
|
275
|
+
Invite a new team member to the project.
|
|
276
|
+
|
|
277
|
+
**Validation:**
|
|
278
|
+
|
|
279
|
+
1. Check email format:
|
|
280
|
+
```javascript
|
|
281
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
282
|
+
if (!emailRegex.test(email)) {
|
|
283
|
+
// Show invalid email error
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
2. Check role is valid:
|
|
288
|
+
```javascript
|
|
289
|
+
const validRoles = ["admin", "editor", "viewer"]
|
|
290
|
+
if (!validRoles.includes(role.toLowerCase())) {
|
|
291
|
+
// Show invalid role error
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**API Call:**
|
|
296
|
+
```bash
|
|
297
|
+
curl -s -X POST \
|
|
298
|
+
-H "Authorization: Bearer {TOKEN}" \
|
|
299
|
+
-H "Content-Type: application/json" \
|
|
300
|
+
-H "Accept: application/json" \
|
|
301
|
+
-d '{"email": "{EMAIL}", "role": "{ROLE}"}' \
|
|
302
|
+
"https://api.planflow.tools/projects/{PROJECT_ID}/team/invite"
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Success Card:**
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
309
|
+
│ ✅ SUCCESS │
|
|
310
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
311
|
+
│ │
|
|
312
|
+
│ {t.commands.team.invite.success} │
|
|
313
|
+
│ │
|
|
314
|
+
│ ── Invitation Details ──────────────────────────────────────────────────── │
|
|
315
|
+
│ │
|
|
316
|
+
│ 📧 {t.commands.team.invite.to} {email} │
|
|
317
|
+
│ 🔑 {t.commands.team.invite.role} {Role} │
|
|
318
|
+
│ 📁 {t.commands.team.invite.project} {projectName} │
|
|
319
|
+
│ │
|
|
320
|
+
│ ╭────────────────────╮ │
|
|
321
|
+
│ │ ✓ Invitation Sent │ │
|
|
322
|
+
│ ╰────────────────────╯ │
|
|
323
|
+
│ │
|
|
324
|
+
│ {t.commands.team.invite.emailSent} │
|
|
325
|
+
│ {t.commands.team.invite.expiresHint} │
|
|
326
|
+
│ │
|
|
327
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
328
|
+
│ │
|
|
329
|
+
│ 💡 {t.ui.labels.commands} │
|
|
330
|
+
│ • /team View pending invitations │
|
|
331
|
+
│ │
|
|
332
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
333
|
+
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**Invalid Email Card:**
|
|
337
|
+
|
|
338
|
+
```
|
|
339
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
340
|
+
│ ❌ ERROR │
|
|
341
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
342
|
+
│ │
|
|
343
|
+
│ {t.commands.team.invite.invalidEmail} │
|
|
344
|
+
│ │
|
|
345
|
+
│ {t.commands.team.invite.emailExample} │
|
|
346
|
+
│ │
|
|
347
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
**Invalid Role Card:**
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
354
|
+
│ ❌ ERROR │
|
|
355
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
356
|
+
│ │
|
|
357
|
+
│ {t.commands.team.invite.invalidRole}: {providedRole} │
|
|
358
|
+
│ │
|
|
359
|
+
│ {t.commands.team.invite.validRoles}: admin, editor, viewer │
|
|
360
|
+
│ │
|
|
361
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Already Member Card (409):**
|
|
365
|
+
|
|
366
|
+
```
|
|
367
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
368
|
+
│ ⚠️ WARNING │
|
|
369
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
370
|
+
│ │
|
|
371
|
+
│ {t.commands.team.invite.alreadyMember} │
|
|
372
|
+
│ │
|
|
373
|
+
│ {email} {t.commands.team.invite.alreadyMemberHint} │
|
|
374
|
+
│ │
|
|
375
|
+
│ 💡 To change their role: │
|
|
376
|
+
│ • /team role {email} <role> │
|
|
377
|
+
│ │
|
|
378
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**Permission Denied Card (403):**
|
|
382
|
+
|
|
383
|
+
```
|
|
384
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
385
|
+
│ ❌ ERROR │
|
|
386
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
387
|
+
│ │
|
|
388
|
+
│ {t.commands.team.invite.noPermission} │
|
|
389
|
+
│ │
|
|
390
|
+
│ {t.commands.team.invite.noPermissionHint} │
|
|
391
|
+
│ │
|
|
392
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**Missing Email Card:**
|
|
396
|
+
|
|
397
|
+
```
|
|
398
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
399
|
+
│ 📨 Team Invite │
|
|
400
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
401
|
+
│ │
|
|
402
|
+
│ ── {t.commands.team.invite.usage} ──────────────────────────────────────── │
|
|
403
|
+
│ │
|
|
404
|
+
│ /team add <email> {t.commands.team.invite.usageDefault} │
|
|
405
|
+
│ /team add <email> <role> {t.commands.team.invite.usageWithRole} │
|
|
406
|
+
│ │
|
|
407
|
+
│ ── {t.commands.team.invite.availableRoles} ─────────────────────────────── │
|
|
408
|
+
│ │
|
|
409
|
+
│ admin - {t.commands.team.invite.roleAdminDesc} │
|
|
410
|
+
│ editor - {t.commands.team.invite.roleEditorDesc} │
|
|
411
|
+
│ viewer - {t.commands.team.invite.roleViewerDesc} │
|
|
412
|
+
│ │
|
|
413
|
+
│ ── {t.commands.team.invite.example} ────────────────────────────────────── │
|
|
414
|
+
│ │
|
|
415
|
+
│ /team add alice@company.com │
|
|
416
|
+
│ /team add bob@company.com admin │
|
|
417
|
+
│ │
|
|
418
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
### Action: role (Change Member Role)
|
|
424
|
+
|
|
425
|
+
Change an existing team member's role.
|
|
426
|
+
|
|
427
|
+
**Validation:**
|
|
428
|
+
|
|
429
|
+
1. Check email is provided
|
|
430
|
+
2. Check role is provided
|
|
431
|
+
3. Check role is valid
|
|
432
|
+
|
|
433
|
+
**API Call:**
|
|
434
|
+
```bash
|
|
435
|
+
curl -s -X PATCH \
|
|
436
|
+
-H "Authorization: Bearer {TOKEN}" \
|
|
437
|
+
-H "Content-Type: application/json" \
|
|
438
|
+
-H "Accept: application/json" \
|
|
439
|
+
-d '{"role": "{ROLE}"}' \
|
|
440
|
+
"https://api.planflow.tools/projects/{PROJECT_ID}/team/{EMAIL}/role"
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
**Success Card:**
|
|
444
|
+
|
|
445
|
+
```
|
|
446
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
447
|
+
│ ✅ SUCCESS │
|
|
448
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
449
|
+
│ │
|
|
450
|
+
│ {t.commands.team.role.success} │
|
|
451
|
+
│ │
|
|
452
|
+
│ ── Role Change Details ─────────────────────────────────────────────────── │
|
|
453
|
+
│ │
|
|
454
|
+
│ 👤 {t.commands.team.role.member}: {memberName} │
|
|
455
|
+
│ 📧 {t.commands.team.role.email}: {email} │
|
|
456
|
+
│ 📁 {t.commands.team.role.project}: {projectName} │
|
|
457
|
+
│ │
|
|
458
|
+
│ ╭─────────────────────────────────╮ │
|
|
459
|
+
│ │ {oldRole} → {newRole} │ │
|
|
460
|
+
│ ╰─────────────────────────────────╯ │
|
|
461
|
+
│ │
|
|
462
|
+
│ {t.commands.team.role.effectiveImmediately} │
|
|
463
|
+
│ │
|
|
464
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
465
|
+
│ │
|
|
466
|
+
│ 💡 {t.ui.labels.commands} │
|
|
467
|
+
│ • /team View all team members │
|
|
468
|
+
│ │
|
|
469
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
470
|
+
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
**Cannot Change Own Role Card:**
|
|
474
|
+
|
|
475
|
+
```
|
|
476
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
477
|
+
│ ❌ ERROR │
|
|
478
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
479
|
+
│ │
|
|
480
|
+
│ {t.commands.team.role.cannotChangeOwnRole} │
|
|
481
|
+
│ │
|
|
482
|
+
│ {t.commands.team.role.cannotChangeOwnRoleHint} │
|
|
483
|
+
│ │
|
|
484
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
**Cannot Change Owner's Role Card (403):**
|
|
488
|
+
|
|
489
|
+
```
|
|
490
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
491
|
+
│ ❌ ERROR │
|
|
492
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
493
|
+
│ │
|
|
494
|
+
│ {t.commands.team.role.cannotChangeOwnerRole} │
|
|
495
|
+
│ │
|
|
496
|
+
│ {t.commands.team.role.cannotChangeOwnerRoleHint} │
|
|
497
|
+
│ │
|
|
498
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
**Member Not Found Card (404):**
|
|
502
|
+
|
|
503
|
+
```
|
|
504
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
505
|
+
│ ❌ ERROR │
|
|
506
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
507
|
+
│ │
|
|
508
|
+
│ {t.commands.team.role.notFound} │
|
|
509
|
+
│ │
|
|
510
|
+
│ {email} {t.commands.team.role.notFoundHint} │
|
|
511
|
+
│ │
|
|
512
|
+
│ 💡 {t.commands.team.role.viewTeam} │
|
|
513
|
+
│ │
|
|
514
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
**Invalid Role Card:**
|
|
518
|
+
|
|
519
|
+
```
|
|
520
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
521
|
+
│ ❌ ERROR │
|
|
522
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
523
|
+
│ │
|
|
524
|
+
│ {t.commands.team.role.invalidRole}: {providedRole} │
|
|
525
|
+
│ │
|
|
526
|
+
│ {t.commands.team.role.validRoles}: admin, editor, viewer │
|
|
527
|
+
│ │
|
|
528
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
**Same Role Card (No Change):**
|
|
532
|
+
|
|
533
|
+
```
|
|
534
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
535
|
+
│ ℹ️ INFO │
|
|
536
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
537
|
+
│ │
|
|
538
|
+
│ {t.commands.team.role.sameRole} │
|
|
539
|
+
│ │
|
|
540
|
+
│ {email} {t.commands.team.role.alreadyHasRole} {role} │
|
|
541
|
+
│ │
|
|
542
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
**Missing Arguments Card:**
|
|
546
|
+
|
|
547
|
+
```
|
|
548
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
549
|
+
│ 🔑 {t.commands.team.role.title} │
|
|
550
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
551
|
+
│ │
|
|
552
|
+
│ ── {t.commands.team.role.usage} ────────────────────────────────────────── │
|
|
553
|
+
│ │
|
|
554
|
+
│ /team role <email> <role> │
|
|
555
|
+
│ │
|
|
556
|
+
│ ── {t.commands.team.role.availableRoles} ───────────────────────────────── │
|
|
557
|
+
│ │
|
|
558
|
+
│ admin - {t.commands.team.invite.roleAdminDesc} │
|
|
559
|
+
│ editor - {t.commands.team.invite.roleEditorDesc} │
|
|
560
|
+
│ viewer - {t.commands.team.invite.roleViewerDesc} │
|
|
561
|
+
│ │
|
|
562
|
+
│ ── {t.commands.team.role.example} ──────────────────────────────────────── │
|
|
563
|
+
│ │
|
|
564
|
+
│ /team role bob@company.com viewer │
|
|
565
|
+
│ /team role alice@company.com admin │
|
|
566
|
+
│ │
|
|
567
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## Error Handling
|
|
573
|
+
|
|
574
|
+
**Network Error Card:**
|
|
575
|
+
|
|
576
|
+
```
|
|
577
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
578
|
+
│ ❌ ERROR │
|
|
579
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
580
|
+
│ │
|
|
581
|
+
│ {t.commands.team.networkError} │
|
|
582
|
+
│ │
|
|
583
|
+
│ Please check your connection and try again. │
|
|
584
|
+
│ │
|
|
585
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
**API Error (403 Forbidden):**
|
|
589
|
+
|
|
590
|
+
```
|
|
591
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
592
|
+
│ ❌ ERROR │
|
|
593
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
594
|
+
│ │
|
|
595
|
+
│ {t.commands.team.noPermission} │
|
|
596
|
+
│ │
|
|
597
|
+
│ Only project members can view the team list. │
|
|
598
|
+
│ │
|
|
599
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
**Authentication Failed (401):**
|
|
603
|
+
|
|
604
|
+
```
|
|
605
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
606
|
+
│ ❌ ERROR │
|
|
607
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
608
|
+
│ │
|
|
609
|
+
│ {t.commands.team.authFailed} │
|
|
610
|
+
│ │
|
|
611
|
+
│ 💡 Please run /pfLogin to re-authenticate. │
|
|
612
|
+
│ │
|
|
613
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
---
|
|
617
|
+
|
|
618
|
+
## Response Parsing
|
|
619
|
+
|
|
620
|
+
### Team List Response
|
|
621
|
+
|
|
622
|
+
```json
|
|
623
|
+
{
|
|
624
|
+
"success": true,
|
|
625
|
+
"data": {
|
|
626
|
+
"project": {
|
|
627
|
+
"id": "uuid",
|
|
628
|
+
"name": "Project Name"
|
|
629
|
+
},
|
|
630
|
+
"members": [
|
|
631
|
+
{
|
|
632
|
+
"id": "uuid",
|
|
633
|
+
"email": "john@company.com",
|
|
634
|
+
"name": "John Doe",
|
|
635
|
+
"role": "owner",
|
|
636
|
+
"status": "active",
|
|
637
|
+
"currentTask": {
|
|
638
|
+
"taskId": "T2.1",
|
|
639
|
+
"name": "API endpoints"
|
|
640
|
+
},
|
|
641
|
+
"lastSeen": "2024-01-15T10:30:00Z"
|
|
642
|
+
}
|
|
643
|
+
],
|
|
644
|
+
"pendingInvites": [
|
|
645
|
+
{
|
|
646
|
+
"email": "alice@company.com",
|
|
647
|
+
"role": "editor",
|
|
648
|
+
"sentAt": "2024-01-13T10:00:00Z"
|
|
649
|
+
}
|
|
650
|
+
]
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
### Invite Response
|
|
656
|
+
|
|
657
|
+
```json
|
|
658
|
+
{
|
|
659
|
+
"success": true,
|
|
660
|
+
"data": {
|
|
661
|
+
"invitation": {
|
|
662
|
+
"email": "alice@company.com",
|
|
663
|
+
"role": "editor",
|
|
664
|
+
"expiresAt": "2024-01-22T10:00:00Z"
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### Role Change Response
|
|
671
|
+
|
|
672
|
+
```json
|
|
673
|
+
{
|
|
674
|
+
"success": true,
|
|
675
|
+
"data": {
|
|
676
|
+
"member": {
|
|
677
|
+
"email": "bob@company.com",
|
|
678
|
+
"name": "Bob Wilson",
|
|
679
|
+
"previousRole": "editor",
|
|
680
|
+
"newRole": "viewer"
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
---
|
|
687
|
+
|
|
688
|
+
## Implementation Notes
|
|
689
|
+
|
|
690
|
+
1. **Role Capitalization**: Display roles with first letter capitalized (Editor, Admin, Viewer)
|
|
691
|
+
2. **Online Status**: Use 🟢 for active (seen within 5 minutes), 🔴 for offline
|
|
692
|
+
3. **Time Formatting**: Use relative time (e.g., "2 hours ago", "3 days ago")
|
|
693
|
+
4. **Current User Highlight**: Show "You" instead of name for the current user
|
|
694
|
+
5. **Email Validation**: Use standard email regex before API call
|
|
695
|
+
6. **Role Validation**: Check against valid roles before API call
|
|
696
|
+
|
|
697
|
+
---
|
|
698
|
+
|
|
699
|
+
## Georgian Translation Example
|
|
700
|
+
|
|
701
|
+
```
|
|
702
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
703
|
+
│ 👥 გუნდის წევრები │
|
|
704
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
705
|
+
│ │
|
|
706
|
+
│ 📁 პროექტი: Planflow Plugin │
|
|
707
|
+
│ │
|
|
708
|
+
│ ── აქტიური წევრები (3) ───────────────────────────────────────────────── │
|
|
709
|
+
│ │
|
|
710
|
+
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
711
|
+
│ │ 🟢 John Doe (მფლობელი) │ │
|
|
712
|
+
│ │ john@company.com │ │
|
|
713
|
+
│ │ მუშაობს: T2.1 - API endpoints │ │
|
|
714
|
+
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
715
|
+
│ │
|
|
716
|
+
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
717
|
+
│ │ 🟢 Jane Smith (ადმინი) │ │
|
|
718
|
+
│ │ jane@company.com │ │
|
|
719
|
+
│ │ მუშაობს: T3.5 - Dashboard │ │
|
|
720
|
+
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
721
|
+
│ │
|
|
722
|
+
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
723
|
+
│ │ 🔴 Bob Wilson (რედაქტორი) │ │
|
|
724
|
+
│ │ bob@company.com │ │
|
|
725
|
+
│ │ ბოლოს ნანახი: 2 საათის წინ │ │
|
|
726
|
+
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
727
|
+
│ │
|
|
728
|
+
│ ── მოლოდინში მყოფი მოწვევები (1) ─────────────────────────────────────── │
|
|
729
|
+
│ │
|
|
730
|
+
│ ⏳ alice@company.com (რედაქტორი) - გაგზავნილი 2 დღის წინ │
|
|
731
|
+
│ │
|
|
732
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
733
|
+
│ │
|
|
734
|
+
│ 💡 ბრძანებები: │
|
|
735
|
+
│ • /team add <email> მოიწვიე გუნდის წევრი │
|
|
736
|
+
│ • /team role <email> <role> შეცვალე წევრის როლი │
|
|
737
|
+
│ │
|
|
738
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
739
|
+
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
740
|
+
```
|