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,623 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pfAssign
|
|
3
|
+
description: Assign a task to a team member in the current PlanFlow project
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PlanFlow Task Assignment
|
|
7
|
+
|
|
8
|
+
Assign a task to a team member or yourself in the linked cloud project.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
/pfAssign <task-id> <email|me> # Assign task to team member or self
|
|
14
|
+
/pfAssign T2.1 jane@company.com # Assign to specific member
|
|
15
|
+
/pfAssign T2.1 me # Assign to yourself
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Process
|
|
19
|
+
|
|
20
|
+
### Step 0: Load User Language & Translations
|
|
21
|
+
|
|
22
|
+
**CRITICAL: Execute this step FIRST, before any output!**
|
|
23
|
+
|
|
24
|
+
Load user's language preference using hierarchical config (local → global → default) and translation file.
|
|
25
|
+
|
|
26
|
+
**Pseudo-code:**
|
|
27
|
+
```javascript
|
|
28
|
+
// Read config with hierarchy AND MERGE
|
|
29
|
+
function getMergedConfig() {
|
|
30
|
+
let globalConfig = {}
|
|
31
|
+
let localConfig = {}
|
|
32
|
+
|
|
33
|
+
// Read global config first (base)
|
|
34
|
+
const globalPath = expandPath("~/.config/claude/plan-plugin-config.json")
|
|
35
|
+
if (fileExists(globalPath)) {
|
|
36
|
+
try {
|
|
37
|
+
globalConfig = JSON.parse(readFile(globalPath))
|
|
38
|
+
} catch (error) {}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Read local config (overrides)
|
|
42
|
+
if (fileExists("./.plan-config.json")) {
|
|
43
|
+
try {
|
|
44
|
+
localConfig = JSON.parse(readFile("./.plan-config.json"))
|
|
45
|
+
} catch (error) {}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Merge configs: local overrides global, but cloud settings are merged
|
|
49
|
+
const mergedConfig = {
|
|
50
|
+
...globalConfig,
|
|
51
|
+
...localConfig,
|
|
52
|
+
cloud: {
|
|
53
|
+
...(globalConfig.cloud || {}),
|
|
54
|
+
...(localConfig.cloud || {})
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return mergedConfig
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const config = getMergedConfig()
|
|
62
|
+
const language = config.language || "en"
|
|
63
|
+
|
|
64
|
+
// Cloud config - properly merged from both configs
|
|
65
|
+
const cloudConfig = config.cloud || {}
|
|
66
|
+
const isAuthenticated = !!cloudConfig.apiToken
|
|
67
|
+
const apiUrl = cloudConfig.apiUrl || "https://api.planflow.tools"
|
|
68
|
+
const projectId = cloudConfig.projectId || null
|
|
69
|
+
const currentUserEmail = cloudConfig.userEmail || null
|
|
70
|
+
|
|
71
|
+
// Load translations
|
|
72
|
+
const translationPath = `locales/${language}.json`
|
|
73
|
+
const t = JSON.parse(readFile(translationPath))
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Instructions for Claude:**
|
|
77
|
+
|
|
78
|
+
1. Read BOTH config files and MERGE them:
|
|
79
|
+
- First read `~/.config/claude/plan-plugin-config.json` (global, base)
|
|
80
|
+
- Then read `./.plan-config.json` (local, overrides)
|
|
81
|
+
- Merge the `cloud` sections: global values + local overrides
|
|
82
|
+
2. Use Read tool: `locales/{language}.json`
|
|
83
|
+
3. Store as `t` variable
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### Step 1: Show Usage Card (if no arguments)
|
|
88
|
+
|
|
89
|
+
If no arguments provided, display usage information.
|
|
90
|
+
|
|
91
|
+
**Output:**
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
95
|
+
│ 📋 Task Assignment │
|
|
96
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
97
|
+
│ │
|
|
98
|
+
│ ── Usage ─────────────────────────────────────────────────────────────── │
|
|
99
|
+
│ │
|
|
100
|
+
│ /pfAssign <task-id> <email> Assign to team member by email │
|
|
101
|
+
│ /pfAssign <task-id> me Assign to yourself │
|
|
102
|
+
│ │
|
|
103
|
+
│ ── Examples ──────────────────────────────────────────────────────────── │
|
|
104
|
+
│ │
|
|
105
|
+
│ /pfAssign T2.1 jane@company.com │
|
|
106
|
+
│ /pfAssign T2.1 me │
|
|
107
|
+
│ │
|
|
108
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Instructions for Claude:**
|
|
112
|
+
|
|
113
|
+
Use translation keys:
|
|
114
|
+
- `t.commands.assign.title`
|
|
115
|
+
- `t.commands.assign.usage`
|
|
116
|
+
- `t.commands.assign.usageEmail`
|
|
117
|
+
- `t.commands.assign.usageMe`
|
|
118
|
+
- `t.commands.assign.example`
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### Step 2: Check Prerequisites
|
|
123
|
+
|
|
124
|
+
Verify user is authenticated and project is linked.
|
|
125
|
+
|
|
126
|
+
**Pseudo-code:**
|
|
127
|
+
```javascript
|
|
128
|
+
if (!isAuthenticated) {
|
|
129
|
+
showError(t.commands.sync.notAuthenticated)
|
|
130
|
+
// "❌ Not authenticated. Run /pfLogin first."
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!projectId) {
|
|
135
|
+
showError(t.commands.sync.notLinked)
|
|
136
|
+
// "❌ Project not linked to cloud. Run /pfCloudLink first."
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Not Authenticated Card:**
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
145
|
+
│ ❌ ERROR │
|
|
146
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
147
|
+
│ │
|
|
148
|
+
│ Not authenticated. │
|
|
149
|
+
│ │
|
|
150
|
+
│ 💡 Run /pfLogin first to authenticate. │
|
|
151
|
+
│ │
|
|
152
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Not Linked Card:**
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
159
|
+
│ ❌ ERROR │
|
|
160
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
161
|
+
│ │
|
|
162
|
+
│ Project not linked to cloud. │
|
|
163
|
+
│ │
|
|
164
|
+
│ 💡 Run /pfCloudLink first to link a project. │
|
|
165
|
+
│ │
|
|
166
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
### Step 3: Parse and Validate Arguments
|
|
172
|
+
|
|
173
|
+
Parse the task ID and assignee from arguments.
|
|
174
|
+
|
|
175
|
+
**Pseudo-code:**
|
|
176
|
+
```javascript
|
|
177
|
+
// Parse arguments: /pfAssign T2.1 jane@company.com
|
|
178
|
+
const args = parseArguments(input) // ["T2.1", "jane@company.com"]
|
|
179
|
+
const taskId = args[0] // "T2.1"
|
|
180
|
+
const assigneeArg = args[1] // "jane@company.com" or "me"
|
|
181
|
+
|
|
182
|
+
// Validate task ID format (T followed by numbers and dots)
|
|
183
|
+
const taskIdRegex = /^T\d+\.\d+$/i
|
|
184
|
+
if (!taskId || !taskIdRegex.test(taskId)) {
|
|
185
|
+
showError(t.commands.assign.invalidTaskId)
|
|
186
|
+
showHint(t.commands.assign.taskIdExample)
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Normalize task ID to uppercase
|
|
191
|
+
const normalizedTaskId = taskId.toUpperCase()
|
|
192
|
+
|
|
193
|
+
// Check assignee argument
|
|
194
|
+
if (!assigneeArg) {
|
|
195
|
+
showError("Missing assignee. Provide an email or 'me'.")
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Determine assignee email
|
|
200
|
+
let assigneeEmail
|
|
201
|
+
if (assigneeArg.toLowerCase() === "me") {
|
|
202
|
+
assigneeEmail = currentUserEmail
|
|
203
|
+
isSelfAssignment = true
|
|
204
|
+
} else {
|
|
205
|
+
// Validate email format
|
|
206
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
207
|
+
if (!emailRegex.test(assigneeArg)) {
|
|
208
|
+
showError(t.commands.assign.invalidEmail)
|
|
209
|
+
showHint(t.commands.assign.emailExample)
|
|
210
|
+
return
|
|
211
|
+
}
|
|
212
|
+
assigneeEmail = assigneeArg.toLowerCase()
|
|
213
|
+
isSelfAssignment = (assigneeEmail === currentUserEmail)
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Invalid Task ID Card:**
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
221
|
+
│ ❌ ERROR │
|
|
222
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
223
|
+
│ │
|
|
224
|
+
│ Invalid task ID format. │
|
|
225
|
+
│ │
|
|
226
|
+
│ Task ID should be like: T1.1, T2.3, T10.5 │
|
|
227
|
+
│ │
|
|
228
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Invalid Email Card:**
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
235
|
+
│ ❌ ERROR │
|
|
236
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
237
|
+
│ │
|
|
238
|
+
│ Invalid email format. │
|
|
239
|
+
│ │
|
|
240
|
+
│ Example: jane@company.com or use 'me' │
|
|
241
|
+
│ │
|
|
242
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### Step 4: Make API Request to Assign Task
|
|
248
|
+
|
|
249
|
+
Call the PlanFlow API to assign the task.
|
|
250
|
+
|
|
251
|
+
**API Endpoint:**
|
|
252
|
+
```
|
|
253
|
+
POST /projects/{projectId}/tasks/{taskId}/assign
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Request Body:**
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"email": "jane@company.com"
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Bash Implementation:**
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
API_URL="https://api.planflow.tools"
|
|
267
|
+
TOKEN="$API_TOKEN"
|
|
268
|
+
PROJECT_ID="$PROJECT_ID"
|
|
269
|
+
TASK_ID="T2.1"
|
|
270
|
+
ASSIGNEE_EMAIL="jane@company.com"
|
|
271
|
+
|
|
272
|
+
RESPONSE=$(curl -s -w "\n%{http_code}" \
|
|
273
|
+
--connect-timeout 5 \
|
|
274
|
+
--max-time 10 \
|
|
275
|
+
-X POST \
|
|
276
|
+
-H "Content-Type: application/json" \
|
|
277
|
+
-H "Accept: application/json" \
|
|
278
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
279
|
+
-d "{\"email\": \"$ASSIGNEE_EMAIL\"}" \
|
|
280
|
+
"${API_URL}/projects/${PROJECT_ID}/tasks/${TASK_ID}/assign")
|
|
281
|
+
|
|
282
|
+
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
|
283
|
+
BODY=$(echo "$RESPONSE" | sed '$d')
|
|
284
|
+
|
|
285
|
+
echo "HTTP Code: $HTTP_CODE"
|
|
286
|
+
echo "Body: $BODY"
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**Instructions for Claude:**
|
|
290
|
+
|
|
291
|
+
1. Make POST request to `/projects/{projectId}/tasks/{taskId}/assign`
|
|
292
|
+
2. Include `{"email": "{assigneeEmail}"}` in body
|
|
293
|
+
3. Parse response to get task and assignee details
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
### Step 5: Handle Response
|
|
298
|
+
|
|
299
|
+
Process the API response and display appropriate card.
|
|
300
|
+
|
|
301
|
+
**Success Response (200):**
|
|
302
|
+
```json
|
|
303
|
+
{
|
|
304
|
+
"success": true,
|
|
305
|
+
"data": {
|
|
306
|
+
"task": {
|
|
307
|
+
"taskId": "T2.1",
|
|
308
|
+
"name": "Implement login API",
|
|
309
|
+
"status": "TODO",
|
|
310
|
+
"assignee": {
|
|
311
|
+
"id": "uuid",
|
|
312
|
+
"email": "jane@company.com",
|
|
313
|
+
"name": "Jane Smith"
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
"project": {
|
|
317
|
+
"id": "uuid",
|
|
318
|
+
"name": "Planflow Plugin"
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
**Pseudo-code for Response Handling:**
|
|
325
|
+
```javascript
|
|
326
|
+
if (httpCode >= 200 && httpCode < 300) {
|
|
327
|
+
const data = JSON.parse(body).data
|
|
328
|
+
const task = data.task
|
|
329
|
+
const project = data.project
|
|
330
|
+
const assignee = task.assignee
|
|
331
|
+
|
|
332
|
+
if (isSelfAssignment) {
|
|
333
|
+
showSelfAssignmentSuccessCard(task, project, currentUserEmail)
|
|
334
|
+
} else {
|
|
335
|
+
showAssignmentSuccessCard(task, project, assignee)
|
|
336
|
+
}
|
|
337
|
+
} else if (httpCode === 404) {
|
|
338
|
+
// Task not found
|
|
339
|
+
showTaskNotFoundCard(taskId)
|
|
340
|
+
} else if (httpCode === 409) {
|
|
341
|
+
// Task already assigned or user not a member
|
|
342
|
+
const error = JSON.parse(body).error
|
|
343
|
+
if (error.code === "ALREADY_ASSIGNED") {
|
|
344
|
+
showAlreadyAssignedCard(taskId, error.currentAssignee)
|
|
345
|
+
} else if (error.code === "USER_NOT_MEMBER") {
|
|
346
|
+
showUserNotMemberCard(assigneeEmail)
|
|
347
|
+
}
|
|
348
|
+
} else if (httpCode === 403) {
|
|
349
|
+
// Permission denied
|
|
350
|
+
showPermissionDeniedCard()
|
|
351
|
+
} else {
|
|
352
|
+
// Other error
|
|
353
|
+
showGenericErrorCard()
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
### Step 6: Display Success Card
|
|
360
|
+
|
|
361
|
+
**Assignment Success Card (to other team member):**
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
365
|
+
│ ✅ SUCCESS │
|
|
366
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
367
|
+
│ │
|
|
368
|
+
│ Task assigned! │
|
|
369
|
+
│ │
|
|
370
|
+
│ ── Assignment Details ────────────────────────────────────────────────── │
|
|
371
|
+
│ │
|
|
372
|
+
│ 📋 Task: T2.1: Implement login API │
|
|
373
|
+
│ 👤 Assigned to: Jane Smith (jane@company.com) │
|
|
374
|
+
│ 📁 Project: Planflow Plugin │
|
|
375
|
+
│ │
|
|
376
|
+
│ ╭───────────────────╮ │
|
|
377
|
+
│ │ ✓ Assigned │ │
|
|
378
|
+
│ ╰───────────────────╯ │
|
|
379
|
+
│ │
|
|
380
|
+
│ They'll be notified of this assignment. │
|
|
381
|
+
│ │
|
|
382
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
383
|
+
│ │
|
|
384
|
+
│ 💡 Commands: │
|
|
385
|
+
│ • /pfUnassign T2.1 Remove assignment │
|
|
386
|
+
│ • /pfWorkload View team workload │
|
|
387
|
+
│ │
|
|
388
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
389
|
+
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**Self-Assignment Success Card:**
|
|
393
|
+
|
|
394
|
+
```
|
|
395
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
396
|
+
│ ✅ SUCCESS │
|
|
397
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
398
|
+
│ │
|
|
399
|
+
│ Task assigned to you! │
|
|
400
|
+
│ │
|
|
401
|
+
│ ── Assignment Details ────────────────────────────────────────────────── │
|
|
402
|
+
│ │
|
|
403
|
+
│ 📋 Task: T2.1: Implement login API │
|
|
404
|
+
│ 👤 Assigned to: You (john@company.com) │
|
|
405
|
+
│ 📁 Project: Planflow Plugin │
|
|
406
|
+
│ │
|
|
407
|
+
│ ╭───────────────────╮ │
|
|
408
|
+
│ │ ✓ Assigned │ │
|
|
409
|
+
│ ╰───────────────────╯ │
|
|
410
|
+
│ │
|
|
411
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
412
|
+
│ │
|
|
413
|
+
│ 💡 Ready to start working? │
|
|
414
|
+
│ • /planUpdate T2.1 start │
|
|
415
|
+
│ │
|
|
416
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
417
|
+
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Instructions for Claude:**
|
|
421
|
+
|
|
422
|
+
Use translation keys:
|
|
423
|
+
- `t.commands.assign.success` - "Task assigned!"
|
|
424
|
+
- `t.commands.assign.task` - "Task:"
|
|
425
|
+
- `t.commands.assign.assignedTo` - "Assigned to:"
|
|
426
|
+
- `t.commands.assign.project` - "Project:"
|
|
427
|
+
- `t.commands.assign.notifyHint` - "They'll be notified of this assignment."
|
|
428
|
+
- `t.commands.assign.selfAssignHint` - "Ready to start working? Run:"
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Error Handling
|
|
433
|
+
|
|
434
|
+
### Task Not Found Card (404)
|
|
435
|
+
|
|
436
|
+
```
|
|
437
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
438
|
+
│ ❌ ERROR │
|
|
439
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
440
|
+
│ │
|
|
441
|
+
│ Task not found: T2.1 │
|
|
442
|
+
│ │
|
|
443
|
+
│ Make sure the task exists in the cloud project. │
|
|
444
|
+
│ │
|
|
445
|
+
│ 💡 Run /pfSyncPush to sync your local tasks first. │
|
|
446
|
+
│ │
|
|
447
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
**Translation keys:**
|
|
451
|
+
- `t.commands.assign.taskNotFound`
|
|
452
|
+
- `t.commands.assign.checkTaskId`
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
### User Not Team Member Card (409 - USER_NOT_MEMBER)
|
|
457
|
+
|
|
458
|
+
```
|
|
459
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
460
|
+
│ ❌ ERROR │
|
|
461
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
462
|
+
│ │
|
|
463
|
+
│ User is not a team member. │
|
|
464
|
+
│ │
|
|
465
|
+
│ jane@company.com is not part of this project. │
|
|
466
|
+
│ │
|
|
467
|
+
│ 💡 Invite them first: │
|
|
468
|
+
│ • /pfTeamInvite jane@company.com │
|
|
469
|
+
│ │
|
|
470
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
**Translation keys:**
|
|
474
|
+
- `t.commands.assign.userNotMember`
|
|
475
|
+
- `t.commands.assign.notMemberHint`
|
|
476
|
+
- `t.commands.assign.inviteFirst`
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
### Task Already Assigned Card (409 - ALREADY_ASSIGNED)
|
|
481
|
+
|
|
482
|
+
```
|
|
483
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
484
|
+
│ ⚠️ WARNING │
|
|
485
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
486
|
+
│ │
|
|
487
|
+
│ Task is already assigned. │
|
|
488
|
+
│ │
|
|
489
|
+
│ T2.1 is currently assigned to Bob Wilson (bob@company.com) │
|
|
490
|
+
│ │
|
|
491
|
+
│ 💡 To reassign: │
|
|
492
|
+
│ • /pfUnassign T2.1 │
|
|
493
|
+
│ • /pfAssign T2.1 jane@company.com │
|
|
494
|
+
│ │
|
|
495
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
**Translation keys:**
|
|
499
|
+
- `t.commands.assign.alreadyAssigned`
|
|
500
|
+
- `t.commands.assign.reassignHint`
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
### Permission Denied Card (403)
|
|
505
|
+
|
|
506
|
+
```
|
|
507
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
508
|
+
│ ❌ ERROR │
|
|
509
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
510
|
+
│ │
|
|
511
|
+
│ You don't have permission to assign tasks. │
|
|
512
|
+
│ │
|
|
513
|
+
│ Only editors and above can assign tasks. │
|
|
514
|
+
│ │
|
|
515
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
**Translation keys:**
|
|
519
|
+
- `t.commands.assign.noPermission`
|
|
520
|
+
- `t.commands.assign.noPermissionHint`
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
### Network Error Card
|
|
525
|
+
|
|
526
|
+
```
|
|
527
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
528
|
+
│ ❌ ERROR │
|
|
529
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
530
|
+
│ │
|
|
531
|
+
│ Could not connect to PlanFlow. │
|
|
532
|
+
│ │
|
|
533
|
+
│ Please check your connection and try again. │
|
|
534
|
+
│ │
|
|
535
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
**Translation keys:**
|
|
539
|
+
- `t.commands.assign.tryAgain`
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
## Complete Flow Diagram
|
|
544
|
+
|
|
545
|
+
```
|
|
546
|
+
/pfAssign T2.1 jane@company.com
|
|
547
|
+
│
|
|
548
|
+
▼
|
|
549
|
+
┌─────────────────────────────────────┐
|
|
550
|
+
│ Step 0: Load config & translations │
|
|
551
|
+
└──────────────┬──────────────────────┘
|
|
552
|
+
│
|
|
553
|
+
▼
|
|
554
|
+
┌─────────────────────────────────────┐
|
|
555
|
+
│ Step 1: Check if args provided │
|
|
556
|
+
│ No args → Show usage card │
|
|
557
|
+
└──────────────┬──────────────────────┘
|
|
558
|
+
│ Has args
|
|
559
|
+
▼
|
|
560
|
+
┌─────────────────────────────────────┐
|
|
561
|
+
│ Step 2: Check prerequisites │
|
|
562
|
+
│ - Authenticated? │
|
|
563
|
+
│ - Project linked? │
|
|
564
|
+
└──────────────┬──────────────────────┘
|
|
565
|
+
│ Yes
|
|
566
|
+
▼
|
|
567
|
+
┌─────────────────────────────────────┐
|
|
568
|
+
│ Step 3: Validate arguments │
|
|
569
|
+
│ - Task ID format │
|
|
570
|
+
│ - Email format or "me" │
|
|
571
|
+
└──────────────┬──────────────────────┘
|
|
572
|
+
│ Valid
|
|
573
|
+
▼
|
|
574
|
+
┌─────────────────────────────────────┐
|
|
575
|
+
│ Step 4: Make API request │
|
|
576
|
+
│ POST /tasks/{id}/assign │
|
|
577
|
+
└──────────────┬──────────────────────┘
|
|
578
|
+
│
|
|
579
|
+
▼
|
|
580
|
+
┌─────────────────────────────────────┐
|
|
581
|
+
│ Step 5: Handle response │
|
|
582
|
+
│ - 200 → Success card │
|
|
583
|
+
│ - 404 → Task not found │
|
|
584
|
+
│ - 409 → Already assigned │
|
|
585
|
+
│ - 403 → Permission denied │
|
|
586
|
+
└─────────────────────────────────────┘
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
---
|
|
590
|
+
|
|
591
|
+
## Georgian Translations Reference
|
|
592
|
+
|
|
593
|
+
For Georgian output, use keys from `locales/ka.json`:
|
|
594
|
+
|
|
595
|
+
```
|
|
596
|
+
📋 ამოცანის მინიჭება
|
|
597
|
+
|
|
598
|
+
გამოყენება:
|
|
599
|
+
/pfAssign <task-id> <email> მინიჭება გუნდის წევრზე ელფოსტით
|
|
600
|
+
/pfAssign <task-id> me მინიჭება საკუთარ თავზე
|
|
601
|
+
|
|
602
|
+
მაგალითები:
|
|
603
|
+
/pfAssign T2.1 jane@company.com
|
|
604
|
+
/pfAssign T2.1 me
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
## Success Criteria
|
|
610
|
+
|
|
611
|
+
A successful implementation should:
|
|
612
|
+
- ✅ Load merged config (global + local)
|
|
613
|
+
- ✅ Load appropriate language translations
|
|
614
|
+
- ✅ Show usage card when no arguments
|
|
615
|
+
- ✅ Validate authentication and project link
|
|
616
|
+
- ✅ Validate task ID format (T1.1, T2.3, etc.)
|
|
617
|
+
- ✅ Validate email format or accept "me"
|
|
618
|
+
- ✅ Handle "me" → current user's email
|
|
619
|
+
- ✅ Make POST request to assign endpoint
|
|
620
|
+
- ✅ Show success card with task and assignee details
|
|
621
|
+
- ✅ Show different card for self-assignment
|
|
622
|
+
- ✅ Handle all error cases with appropriate cards
|
|
623
|
+
- ✅ Use translation keys for all user-facing text
|