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,1200 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: planNext
|
|
3
|
+
description: Plan Next Task Recommendation
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Plan Next Task Recommendation
|
|
7
|
+
|
|
8
|
+
You are an intelligent task prioritization assistant. Your role is to analyze the project plan and recommend the best next task to work on.
|
|
9
|
+
|
|
10
|
+
## Objective
|
|
11
|
+
|
|
12
|
+
Analyze PROJECT_PLAN.md to find the optimal next task based on dependencies, current phase, complexity, and project momentum.
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
/planNext
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
No arguments needed - analyzes the entire project state.
|
|
21
|
+
|
|
22
|
+
## Process
|
|
23
|
+
|
|
24
|
+
### Step 0: Load User Language & Translations
|
|
25
|
+
|
|
26
|
+
**CRITICAL: Execute this step FIRST, before any output!**
|
|
27
|
+
|
|
28
|
+
Load user's language preference using hierarchical config (local → global → default) and translation file.
|
|
29
|
+
|
|
30
|
+
**Pseudo-code:**
|
|
31
|
+
```javascript
|
|
32
|
+
// Read config with hierarchy (v1.1.1+)
|
|
33
|
+
function getConfig() {
|
|
34
|
+
// Try local config first
|
|
35
|
+
if (fileExists("./.plan-config.json")) {
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(readFile("./.plan-config.json"))
|
|
38
|
+
} catch (error) {}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Fall back to global config
|
|
42
|
+
const globalPath = expandPath("~/.config/claude/plan-plugin-config.json")
|
|
43
|
+
if (fileExists(globalPath)) {
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(readFile(globalPath))
|
|
46
|
+
} catch (error) {}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Fall back to defaults
|
|
50
|
+
return { "language": "en" }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const config = getConfig()
|
|
54
|
+
const language = config.language || "en"
|
|
55
|
+
|
|
56
|
+
// Cloud config (v1.2.0+) - MERGE global and local configs
|
|
57
|
+
function getMergedConfig() {
|
|
58
|
+
let globalConfig = {}
|
|
59
|
+
let localConfig = {}
|
|
60
|
+
|
|
61
|
+
const globalPath = expandPath("~/.config/claude/plan-plugin-config.json")
|
|
62
|
+
if (fileExists(globalPath)) {
|
|
63
|
+
try { globalConfig = JSON.parse(readFile(globalPath)) } catch (e) {}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (fileExists("./.plan-config.json")) {
|
|
67
|
+
try { localConfig = JSON.parse(readFile("./.plan-config.json")) } catch (e) {}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
...globalConfig,
|
|
72
|
+
...localConfig,
|
|
73
|
+
cloud: {
|
|
74
|
+
...(globalConfig.cloud || {}),
|
|
75
|
+
...(localConfig.cloud || {})
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const mergedConfig = getMergedConfig()
|
|
81
|
+
const cloudConfig = mergedConfig.cloud || {}
|
|
82
|
+
const isAuthenticated = !!cloudConfig.apiToken
|
|
83
|
+
const apiUrl = cloudConfig.apiUrl || "https://api.planflow.tools"
|
|
84
|
+
const autoSync = cloudConfig.autoSync || false
|
|
85
|
+
const projectId = cloudConfig.projectId || null
|
|
86
|
+
const currentUserEmail = cloudConfig.userEmail || null
|
|
87
|
+
|
|
88
|
+
// Load translations
|
|
89
|
+
const translationPath = `locales/${language}.json`
|
|
90
|
+
const t = JSON.parse(readFile(translationPath))
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Instructions for Claude:**
|
|
94
|
+
|
|
95
|
+
1. Try to read `./.plan-config.json` (local, highest priority)
|
|
96
|
+
2. If not found/corrupted, try `~/.config/claude/plan-plugin-config.json` (global)
|
|
97
|
+
3. If not found/corrupted, use default: `language = "en"`
|
|
98
|
+
4. Use Read tool: `locales/{language}.json`
|
|
99
|
+
5. Store as `t` variable
|
|
100
|
+
|
|
101
|
+
### Step 0.5: Show Notification Badge (v1.6.0+)
|
|
102
|
+
|
|
103
|
+
**Purpose:** Display unread notification count to keep users informed of team activity.
|
|
104
|
+
|
|
105
|
+
**When to Execute:** Only if authenticated AND linked to a project.
|
|
106
|
+
|
|
107
|
+
**Pseudo-code:**
|
|
108
|
+
```javascript
|
|
109
|
+
async function showNotificationBadge(cloudConfig, t) {
|
|
110
|
+
// Skip if not authenticated or not linked
|
|
111
|
+
if (!cloudConfig.apiToken || !cloudConfig.projectId) {
|
|
112
|
+
return // Silently skip
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const apiUrl = cloudConfig.apiUrl || "https://api.planflow.tools"
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
// Fetch unread count (lightweight call with short timeout)
|
|
119
|
+
const response = await fetch(
|
|
120
|
+
`${apiUrl}/projects/${cloudConfig.projectId}/notifications?limit=1&unread=true`,
|
|
121
|
+
{
|
|
122
|
+
method: "GET",
|
|
123
|
+
headers: {
|
|
124
|
+
"Authorization": `Bearer ${cloudConfig.apiToken}`,
|
|
125
|
+
"Accept": "application/json"
|
|
126
|
+
},
|
|
127
|
+
timeout: 5000 // 5 second max
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if (response.ok) {
|
|
132
|
+
const data = response.data
|
|
133
|
+
const unreadCount = data.unreadCount || 0
|
|
134
|
+
|
|
135
|
+
if (unreadCount > 0) {
|
|
136
|
+
// Display badge
|
|
137
|
+
const label = unreadCount === 1
|
|
138
|
+
? t.skills.notificationBadge.unreadOne
|
|
139
|
+
: t.skills.notificationBadge.unreadMultiple
|
|
140
|
+
console.log(`🔔 ${unreadCount} ${label} — /pfNotifications ${t.skills.notificationBadge.toView}`)
|
|
141
|
+
console.log("") // Blank line before main output
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
// Silently fail - don't block the command
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Bash Implementation:**
|
|
151
|
+
```bash
|
|
152
|
+
API_URL="https://api.planflow.tools"
|
|
153
|
+
TOKEN="$API_TOKEN"
|
|
154
|
+
PROJECT_ID="$PROJECT_ID"
|
|
155
|
+
|
|
156
|
+
# Only proceed if authenticated and linked
|
|
157
|
+
if [ -n "$TOKEN" ] && [ -n "$PROJECT_ID" ]; then
|
|
158
|
+
# Fetch unread count with short timeout
|
|
159
|
+
RESPONSE=$(curl -s --connect-timeout 3 --max-time 5 \
|
|
160
|
+
-X GET \
|
|
161
|
+
-H "Accept: application/json" \
|
|
162
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
163
|
+
"${API_URL}/projects/${PROJECT_ID}/notifications?limit=1&unread=true" 2>/dev/null)
|
|
164
|
+
|
|
165
|
+
if [ $? -eq 0 ]; then
|
|
166
|
+
UNREAD_COUNT=$(echo "$RESPONSE" | grep -o '"unreadCount":[0-9]*' | grep -o '[0-9]*')
|
|
167
|
+
if [ -n "$UNREAD_COUNT" ] && [ "$UNREAD_COUNT" -gt 0 ]; then
|
|
168
|
+
echo "🔔 $UNREAD_COUNT unread notification(s) — /pfNotifications to view"
|
|
169
|
+
echo ""
|
|
170
|
+
fi
|
|
171
|
+
fi
|
|
172
|
+
fi
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Example Output (if 3 unread):**
|
|
176
|
+
```
|
|
177
|
+
🔔 3 unread notifications — /pfNotifications to view
|
|
178
|
+
|
|
179
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
180
|
+
│ 🎯 Recommended Next Task │
|
|
181
|
+
...
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Instructions for Claude:**
|
|
185
|
+
|
|
186
|
+
1. After loading config and translations (Step 0), check if `cloudConfig.apiToken` AND `cloudConfig.projectId` exist
|
|
187
|
+
2. If yes, make a quick API call to fetch notification count
|
|
188
|
+
3. If unreadCount > 0, display the badge line with a blank line after
|
|
189
|
+
4. If any error occurs (timeout, network, auth), silently skip and continue
|
|
190
|
+
5. Proceed to Step 1 regardless of badge result
|
|
191
|
+
|
|
192
|
+
**Important:** Never let this step block or delay the main command. Use short timeouts and fail silently.
|
|
193
|
+
|
|
194
|
+
### Step 1: Read PROJECT_PLAN.md
|
|
195
|
+
|
|
196
|
+
Use the Read tool to read PROJECT_PLAN.md from the current working directory.
|
|
197
|
+
|
|
198
|
+
If file doesn't exist, output:
|
|
199
|
+
```
|
|
200
|
+
{t.commands.update.planNotFound}
|
|
201
|
+
|
|
202
|
+
{t.commands.update.runPlanNew}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Example:**
|
|
206
|
+
- EN: "❌ Error: PROJECT_PLAN.md not found in current directory. Please run /planNew first to create a project plan."
|
|
207
|
+
- KA: "❌ შეცდომა: PROJECT_PLAN.md არ მოიძებნა მიმდინარე დირექტორიაში. გთხოვთ ჯერ გაუშვათ /planNew პროექტის გეგმის შესაქმნელად."
|
|
208
|
+
|
|
209
|
+
### Step 2: Parse All Tasks
|
|
210
|
+
|
|
211
|
+
Extract all tasks with their properties:
|
|
212
|
+
|
|
213
|
+
For each task (`#### TX.Y: Task Name`), extract:
|
|
214
|
+
- **Task ID**: e.g., T1.1
|
|
215
|
+
- **Task Name**: e.g., "Project Setup"
|
|
216
|
+
- **Status**: TODO, IN_PROGRESS, DONE, BLOCKED
|
|
217
|
+
- **Complexity**: Low, Medium, High
|
|
218
|
+
- **Estimated**: Hours (e.g., "2 hours")
|
|
219
|
+
- **Dependencies**: List of task IDs or "None"
|
|
220
|
+
- **Phase**: Derived from task ID (T1.X = Phase 1, T2.X = Phase 2, etc.)
|
|
221
|
+
- **Description**: Task details
|
|
222
|
+
|
|
223
|
+
Create a mental model of all tasks.
|
|
224
|
+
|
|
225
|
+
### Step 3: Filter Available Tasks
|
|
226
|
+
|
|
227
|
+
A task is **available** if:
|
|
228
|
+
1. ✅ Status is TODO (not DONE, not IN_PROGRESS, not BLOCKED)
|
|
229
|
+
2. ✅ All dependencies are completed (status = DONE)
|
|
230
|
+
3. ✅ Task is in current phase or earlier incomplete phase
|
|
231
|
+
|
|
232
|
+
**Current Phase** = Lowest phase number that still has incomplete tasks
|
|
233
|
+
|
|
234
|
+
Example:
|
|
235
|
+
- Phase 1: 3/4 tasks done → Phase 1 is current
|
|
236
|
+
- Phase 2: 0/5 tasks done → Not current yet
|
|
237
|
+
- Phase 3: 0/3 tasks done → Not current yet
|
|
238
|
+
|
|
239
|
+
### Step 4: Rank Available Tasks
|
|
240
|
+
|
|
241
|
+
Score each available task using multiple factors:
|
|
242
|
+
|
|
243
|
+
#### Factor 1: Phase Priority (Weight: 40%)
|
|
244
|
+
```
|
|
245
|
+
Score = 100 if in current phase
|
|
246
|
+
Score = 50 if in next phase
|
|
247
|
+
Score = 0 if beyond next phase
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Complete earlier phases before starting later ones (mostly).
|
|
251
|
+
|
|
252
|
+
#### Factor 2: Dependency Impact (Weight: 30%)
|
|
253
|
+
```
|
|
254
|
+
Count how many tasks depend on this task (directly or indirectly)
|
|
255
|
+
Score = (dependent_count / max_dependent_count) × 100
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Prioritize tasks that unlock many others (critical path).
|
|
259
|
+
|
|
260
|
+
#### Factor 3: Complexity Balance (Weight: 20%)
|
|
261
|
+
```
|
|
262
|
+
Check recently completed tasks' complexity:
|
|
263
|
+
- If last task was High → prefer Low or Medium (Score: 100)
|
|
264
|
+
- If last task was Low → prefer Medium or High (Score: 100)
|
|
265
|
+
- Otherwise → Medium complexity gets Score: 100
|
|
266
|
+
|
|
267
|
+
Prevents burnout and maintains momentum.
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
#### Factor 4: Natural Flow (Weight: 10%)
|
|
271
|
+
```
|
|
272
|
+
Score = 100 if task ID is sequential (e.g., T1.1, T1.2, T1.3)
|
|
273
|
+
Score = 50 otherwise
|
|
274
|
+
|
|
275
|
+
Following sequential order often makes sense.
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
#### Calculate Total Score
|
|
279
|
+
```
|
|
280
|
+
Total = (Phase × 0.4) + (Dependencies × 0.3) + (Complexity × 0.2) + (Flow × 0.1)
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Sort tasks by total score (highest first).
|
|
284
|
+
|
|
285
|
+
### Step 5: Select Top Recommendation
|
|
286
|
+
|
|
287
|
+
Pick the highest-scored task as the primary recommendation.
|
|
288
|
+
|
|
289
|
+
Also identify 2-3 alternative tasks (next highest scores).
|
|
290
|
+
|
|
291
|
+
### Step 5.5: Fetch Task Assignments (v1.6.0+)
|
|
292
|
+
|
|
293
|
+
If authenticated and linked to a cloud project, fetch task assignments to show who is working on what.
|
|
294
|
+
|
|
295
|
+
**Pseudo-code:**
|
|
296
|
+
```javascript
|
|
297
|
+
let taskAssignments = {} // Map of taskId -> assignee info
|
|
298
|
+
|
|
299
|
+
if (isAuthenticated && projectId) {
|
|
300
|
+
// Fetch tasks with assignments from cloud
|
|
301
|
+
const response = await fetch(
|
|
302
|
+
`${apiUrl}/projects/${projectId}/tasks`,
|
|
303
|
+
{
|
|
304
|
+
method: "GET",
|
|
305
|
+
headers: {
|
|
306
|
+
"Authorization": `Bearer ${cloudConfig.apiToken}`,
|
|
307
|
+
"Accept": "application/json"
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
if (response.ok) {
|
|
313
|
+
const data = response.data
|
|
314
|
+
const tasks = data.tasks || []
|
|
315
|
+
|
|
316
|
+
for (const task of tasks) {
|
|
317
|
+
if (task.assignee) {
|
|
318
|
+
taskAssignments[task.taskId] = {
|
|
319
|
+
email: task.assignee.email,
|
|
320
|
+
name: task.assignee.name || task.assignee.email,
|
|
321
|
+
isCurrentUser: task.assignee.email === currentUserEmail
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**Bash Implementation:**
|
|
330
|
+
```bash
|
|
331
|
+
API_URL="https://api.planflow.tools"
|
|
332
|
+
TOKEN="$API_TOKEN"
|
|
333
|
+
PROJECT_ID="$PROJECT_ID"
|
|
334
|
+
|
|
335
|
+
# Fetch tasks with assignments
|
|
336
|
+
RESPONSE=$(curl -s \
|
|
337
|
+
--connect-timeout 5 \
|
|
338
|
+
--max-time 10 \
|
|
339
|
+
-X GET \
|
|
340
|
+
-H "Accept: application/json" \
|
|
341
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
342
|
+
"${API_URL}/projects/${PROJECT_ID}/tasks")
|
|
343
|
+
|
|
344
|
+
# Parse assignee info from response
|
|
345
|
+
# Each task has: taskId, assignee: { email, name }
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**Instructions for Claude:**
|
|
349
|
+
|
|
350
|
+
1. Only fetch assignments if authenticated AND projectId exists
|
|
351
|
+
2. Use a short timeout (5s connect, 10s max) to avoid blocking
|
|
352
|
+
3. If fetch fails, continue without assignments (graceful degradation)
|
|
353
|
+
4. Store assignments in a map for quick lookup by taskId
|
|
354
|
+
5. Track if assignee is the current user for special messaging
|
|
355
|
+
|
|
356
|
+
### Step 5.6: Fetch GitHub Status (v1.6.0+ - T13.6)
|
|
357
|
+
|
|
358
|
+
If authenticated, linked to a cloud project, and GitHub is integrated, fetch GitHub-related data for tasks (branches, issues, PRs).
|
|
359
|
+
|
|
360
|
+
**Pseudo-code:**
|
|
361
|
+
```javascript
|
|
362
|
+
let githubIntegration = null // GitHub integration info
|
|
363
|
+
let taskGithubStatus = {} // Map of taskId -> { branch, issue, pr }
|
|
364
|
+
|
|
365
|
+
if (isAuthenticated && projectId) {
|
|
366
|
+
// Step 1: Check if GitHub is integrated
|
|
367
|
+
const integrationResponse = await fetch(
|
|
368
|
+
`${apiUrl}/projects/${projectId}/integrations/github`,
|
|
369
|
+
{
|
|
370
|
+
method: "GET",
|
|
371
|
+
headers: {
|
|
372
|
+
"Authorization": `Bearer ${cloudConfig.apiToken}`,
|
|
373
|
+
"Accept": "application/json"
|
|
374
|
+
},
|
|
375
|
+
timeout: 5000
|
|
376
|
+
}
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
if (integrationResponse.ok) {
|
|
380
|
+
const data = integrationResponse.data
|
|
381
|
+
if (data.owner && data.repo) {
|
|
382
|
+
githubIntegration = {
|
|
383
|
+
owner: data.owner,
|
|
384
|
+
repo: data.repo,
|
|
385
|
+
url: `https://github.com/${data.owner}/${data.repo}`
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Step 2: Fetch GitHub status for all tasks
|
|
389
|
+
const githubStatusResponse = await fetch(
|
|
390
|
+
`${apiUrl}/projects/${projectId}/github/status`,
|
|
391
|
+
{
|
|
392
|
+
method: "GET",
|
|
393
|
+
headers: {
|
|
394
|
+
"Authorization": `Bearer ${cloudConfig.apiToken}`,
|
|
395
|
+
"Accept": "application/json"
|
|
396
|
+
},
|
|
397
|
+
timeout: 5000
|
|
398
|
+
}
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
if (githubStatusResponse.ok) {
|
|
402
|
+
const statusData = githubStatusResponse.data
|
|
403
|
+
const tasks = statusData.tasks || []
|
|
404
|
+
|
|
405
|
+
for (const task of tasks) {
|
|
406
|
+
taskGithubStatus[task.taskId] = {
|
|
407
|
+
branch: task.branch || null, // e.g., "feature/T2.1-implement-login"
|
|
408
|
+
issue: task.issue || null, // e.g., { number: 42, state: "open", url: "..." }
|
|
409
|
+
pr: task.pr || null // e.g., { number: 45, state: "open", url: "...", reviewStatus: "awaiting" }
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
**Bash Implementation:**
|
|
419
|
+
```bash
|
|
420
|
+
API_URL="https://api.planflow.tools"
|
|
421
|
+
TOKEN="$API_TOKEN"
|
|
422
|
+
PROJECT_ID="$PROJECT_ID"
|
|
423
|
+
|
|
424
|
+
# Step 1: Check if GitHub is integrated
|
|
425
|
+
GITHUB_RESPONSE=$(curl -s --connect-timeout 3 --max-time 5 \
|
|
426
|
+
-X GET \
|
|
427
|
+
-H "Accept: application/json" \
|
|
428
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
429
|
+
"${API_URL}/projects/${PROJECT_ID}/integrations/github" 2>/dev/null)
|
|
430
|
+
|
|
431
|
+
GITHUB_OWNER=$(echo "$GITHUB_RESPONSE" | jq -r '.data.owner // empty' 2>/dev/null)
|
|
432
|
+
GITHUB_REPO=$(echo "$GITHUB_RESPONSE" | jq -r '.data.repo // empty' 2>/dev/null)
|
|
433
|
+
|
|
434
|
+
if [ -n "$GITHUB_OWNER" ] && [ -n "$GITHUB_REPO" ]; then
|
|
435
|
+
GITHUB_LINKED=true
|
|
436
|
+
|
|
437
|
+
# Step 2: Fetch task GitHub status
|
|
438
|
+
STATUS_RESPONSE=$(curl -s --connect-timeout 3 --max-time 5 \
|
|
439
|
+
-X GET \
|
|
440
|
+
-H "Accept: application/json" \
|
|
441
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
442
|
+
"${API_URL}/projects/${PROJECT_ID}/github/status" 2>/dev/null)
|
|
443
|
+
|
|
444
|
+
# Parse GitHub status for each task
|
|
445
|
+
# Response format: { tasks: [{ taskId, branch, issue: { number, state }, pr: { number, state, reviewStatus } }] }
|
|
446
|
+
fi
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**Fallback: Check Local Git Repository:**
|
|
450
|
+
|
|
451
|
+
If cloud GitHub status is unavailable, check for local branches:
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
# Check if we're in a git repo and have branches for tasks
|
|
455
|
+
if git rev-parse --git-dir > /dev/null 2>&1; then
|
|
456
|
+
for TASK_ID in $RECOMMENDED_TASKS; do
|
|
457
|
+
# Check for branches matching pattern: feature/T1.1-*, feat/T1.1-*, T1.1-*
|
|
458
|
+
BRANCH=$(git branch --list "feature/${TASK_ID}-*" "feat/${TASK_ID}-*" "${TASK_ID}-*" 2>/dev/null | head -1 | sed 's/^[* ]*//')
|
|
459
|
+
if [ -n "$BRANCH" ]; then
|
|
460
|
+
TASK_BRANCHES["$TASK_ID"]="$BRANCH"
|
|
461
|
+
fi
|
|
462
|
+
done
|
|
463
|
+
fi
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
**Instructions for Claude:**
|
|
467
|
+
|
|
468
|
+
1. Only fetch GitHub status if authenticated AND projectId exists
|
|
469
|
+
2. First check if GitHub is integrated (via `/integrations/github`)
|
|
470
|
+
3. If integrated, fetch task-specific GitHub data (via `/github/status`)
|
|
471
|
+
4. Use short timeouts (3s connect, 5s max) to avoid blocking
|
|
472
|
+
5. If cloud fetch fails, try to detect local branches as fallback
|
|
473
|
+
6. Store status in a map for quick lookup by taskId
|
|
474
|
+
7. Continue without GitHub status if any step fails (graceful degradation)
|
|
475
|
+
|
|
476
|
+
### Step 6: Generate Recommendation
|
|
477
|
+
|
|
478
|
+
Display a detailed recommendation using translations.
|
|
479
|
+
|
|
480
|
+
**Pseudo-code:**
|
|
481
|
+
```javascript
|
|
482
|
+
const task = recommendedTask
|
|
483
|
+
const complexityText = t.templates.complexity[task.complexity.toLowerCase()]
|
|
484
|
+
// EN: "Low", "Medium", "High"
|
|
485
|
+
// KA: "დაბალი", "საშუალო", "მაღალი"
|
|
486
|
+
|
|
487
|
+
// Get assignee info for this task (v1.6.0+)
|
|
488
|
+
const assignee = taskAssignments[`T${task.id}`] || null
|
|
489
|
+
|
|
490
|
+
// Get GitHub status for this task (v1.6.0+ T13.6)
|
|
491
|
+
const github = taskGithubStatus[`T${task.id}`] || null
|
|
492
|
+
|
|
493
|
+
let output = t.commands.next.title + "\n\n"
|
|
494
|
+
output += t.commands.next.recommendedTask + "\n"
|
|
495
|
+
output += `T${task.id}: ${task.name}\n\n`
|
|
496
|
+
output += t.commands.next.complexity + " " + complexityText + "\n"
|
|
497
|
+
output += t.commands.next.estimated + " " + task.estimated + "\n"
|
|
498
|
+
output += t.commands.next.phase + " " + task.phase + "\n"
|
|
499
|
+
|
|
500
|
+
// Show assignee (v1.6.0+)
|
|
501
|
+
if (assignee) {
|
|
502
|
+
if (assignee.isCurrentUser) {
|
|
503
|
+
output += t.commands.next.assignedToYou + "\n"
|
|
504
|
+
} else {
|
|
505
|
+
output += t.commands.next.assignedTo + " " + assignee.name + "\n"
|
|
506
|
+
}
|
|
507
|
+
} else {
|
|
508
|
+
output += t.commands.next.unassigned + "\n"
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Show GitHub status (v1.6.0+ T13.6)
|
|
512
|
+
if (githubIntegration && github) {
|
|
513
|
+
output += formatGithubStatus(github, t)
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
output += "\n" + t.commands.next.dependenciesCompleted + "\n\n"
|
|
517
|
+
output += t.commands.next.whyThisTask + "\n"
|
|
518
|
+
output += reasons.map(r => "• " + r).join("\n") + "\n"
|
|
519
|
+
|
|
520
|
+
// Add assignee-specific hints (v1.6.0+)
|
|
521
|
+
if (assignee && !assignee.isCurrentUser) {
|
|
522
|
+
output += "• " + t.commands.next.assignedHint + "\n"
|
|
523
|
+
} else if (assignee && assignee.isCurrentUser) {
|
|
524
|
+
output += "• " + t.commands.next.youAreAssigned + "\n"
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
output += "\n" + t.commands.next.taskDetails + "\n"
|
|
528
|
+
output += task.description + "\n\n"
|
|
529
|
+
output += t.commands.next.readyToStart + "\n"
|
|
530
|
+
output += `/planUpdate T${task.id} start\n\n`
|
|
531
|
+
output += "─".repeat(60) + "\n\n"
|
|
532
|
+
output += t.commands.next.alternatives + "\n\n"
|
|
533
|
+
|
|
534
|
+
// Show assignee and GitHub status in alternatives too (v1.6.0+)
|
|
535
|
+
output += alternatives.map((alt, i) => {
|
|
536
|
+
const altAssignee = taskAssignments[`T${alt.id}`]
|
|
537
|
+
const altGithub = taskGithubStatus[`T${alt.id}`]
|
|
538
|
+
let suffixInfo = ""
|
|
539
|
+
|
|
540
|
+
// Add assignee info
|
|
541
|
+
if (altAssignee) {
|
|
542
|
+
if (altAssignee.isCurrentUser) {
|
|
543
|
+
suffixInfo += " 👤 (you)"
|
|
544
|
+
} else {
|
|
545
|
+
suffixInfo += ` 👤 ${altAssignee.name}`
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Add compact GitHub info
|
|
550
|
+
if (githubIntegration && altGithub) {
|
|
551
|
+
suffixInfo += formatGithubStatusCompact(altGithub)
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
return `${i+1}. T${alt.id}: ${alt.name} - ${alt.complexity} - ${alt.estimated}${suffixInfo}`
|
|
555
|
+
}).join("\n")
|
|
556
|
+
|
|
557
|
+
// Helper function to format GitHub status for main recommendation
|
|
558
|
+
function formatGithubStatus(github, t) {
|
|
559
|
+
let output = ""
|
|
560
|
+
|
|
561
|
+
if (github.branch) {
|
|
562
|
+
// Show branch name (truncate if too long)
|
|
563
|
+
const branchName = github.branch.length > 35
|
|
564
|
+
? github.branch.substring(0, 32) + "..."
|
|
565
|
+
: github.branch
|
|
566
|
+
output += ` 🌿 ${t.commands.next.github.branch}: ${branchName}\n`
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
if (github.issue) {
|
|
570
|
+
const issueState = github.issue.state === "open"
|
|
571
|
+
? t.commands.next.github.open
|
|
572
|
+
: t.commands.next.github.closed
|
|
573
|
+
output += ` 📋 ${t.commands.next.github.issue}: #${github.issue.number} (${issueState})\n`
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if (github.pr) {
|
|
577
|
+
let prStatus = ""
|
|
578
|
+
if (github.pr.state === "merged") {
|
|
579
|
+
prStatus = t.commands.next.github.merged
|
|
580
|
+
} else if (github.pr.state === "closed") {
|
|
581
|
+
prStatus = t.commands.next.github.closed
|
|
582
|
+
} else if (github.pr.reviewStatus === "approved") {
|
|
583
|
+
prStatus = t.commands.next.github.approved
|
|
584
|
+
} else if (github.pr.reviewStatus === "changes_requested") {
|
|
585
|
+
prStatus = t.commands.next.github.changesRequested
|
|
586
|
+
} else if (github.pr.reviewStatus === "awaiting") {
|
|
587
|
+
prStatus = t.commands.next.github.awaitingReview
|
|
588
|
+
} else {
|
|
589
|
+
prStatus = t.commands.next.github.open
|
|
590
|
+
}
|
|
591
|
+
output += ` 🔀 ${t.commands.next.github.pr}: #${github.pr.number} (${prStatus})\n`
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
if (!github.branch && !github.issue && !github.pr) {
|
|
595
|
+
// No GitHub activity yet
|
|
596
|
+
output += ` 🐙 ${t.commands.next.github.noActivity}\n`
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
return output
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// Helper function for compact GitHub status (used in alternatives list)
|
|
603
|
+
function formatGithubStatusCompact(github) {
|
|
604
|
+
const parts = []
|
|
605
|
+
|
|
606
|
+
if (github.branch) {
|
|
607
|
+
parts.push("🌿") // Has branch
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
if (github.issue) {
|
|
611
|
+
const state = github.issue.state === "open" ? "" : "✓"
|
|
612
|
+
parts.push(`#${github.issue.number}${state}`)
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (github.pr) {
|
|
616
|
+
let prIcon = "🔀"
|
|
617
|
+
if (github.pr.state === "merged") {
|
|
618
|
+
prIcon = "✅"
|
|
619
|
+
} else if (github.pr.reviewStatus === "approved") {
|
|
620
|
+
prIcon = "👍"
|
|
621
|
+
} else if (github.pr.reviewStatus === "changes_requested") {
|
|
622
|
+
prIcon = "⚠️"
|
|
623
|
+
}
|
|
624
|
+
parts.push(`${prIcon}PR#${github.pr.number}`)
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
return parts.length > 0 ? ` [${parts.join(" ")}]` : ""
|
|
628
|
+
}
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
**Example output (English - Unassigned task, no GitHub activity):**
|
|
632
|
+
|
|
633
|
+
```
|
|
634
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
635
|
+
│ 🎯 Recommended Next Task │
|
|
636
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
637
|
+
│ │
|
|
638
|
+
│ T1.2: Database Setup │
|
|
639
|
+
│ │
|
|
640
|
+
│ ── Task Details ────────────────────────────────────────────────────────── │
|
|
641
|
+
│ │
|
|
642
|
+
│ 📊 Complexity: Medium │
|
|
643
|
+
│ ⏱️ Estimated: 4 hours │
|
|
644
|
+
│ 🎯 Phase: 1 - Foundation │
|
|
645
|
+
│ 👤 Assigned: Unassigned │
|
|
646
|
+
│ 🐙 GitHub: No activity yet │
|
|
647
|
+
│ │
|
|
648
|
+
│ ✅ All dependencies completed │
|
|
649
|
+
│ │
|
|
650
|
+
│ ── Why This Task? ──────────────────────────────────────────────────────── │
|
|
651
|
+
│ │
|
|
652
|
+
│ • Unlocks 3 other tasks │
|
|
653
|
+
│ • Critical for Phase 2 progress │
|
|
654
|
+
│ • Good complexity balance after previous task │
|
|
655
|
+
│ │
|
|
656
|
+
│ ── Description ─────────────────────────────────────────────────────────── │
|
|
657
|
+
│ │
|
|
658
|
+
│ Configure PostgreSQL database with connection pooling │
|
|
659
|
+
│ and initial schema setup... │
|
|
660
|
+
│ │
|
|
661
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
662
|
+
│ │
|
|
663
|
+
│ 💡 Ready to start? │
|
|
664
|
+
│ • /planUpdate T1.2 start │
|
|
665
|
+
│ • /pfGithubBranch T1.2 Create a branch │
|
|
666
|
+
│ │
|
|
667
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
668
|
+
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
669
|
+
|
|
670
|
+
── Alternative Tasks ────────────────────────────────────────────────────────
|
|
671
|
+
|
|
672
|
+
1. T1.3: Authentication Setup - High - 6 hours
|
|
673
|
+
2. T2.1: API Endpoints - Medium - 5 hours 👤 jane@company.com [🌿 #42]
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
**Example output (English - With GitHub branch, issue, and PR):**
|
|
677
|
+
|
|
678
|
+
```
|
|
679
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
680
|
+
│ 🎯 Recommended Next Task │
|
|
681
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
682
|
+
│ │
|
|
683
|
+
│ T2.1: Implement Login API │
|
|
684
|
+
│ │
|
|
685
|
+
│ ── Task Details ────────────────────────────────────────────────────────── │
|
|
686
|
+
│ │
|
|
687
|
+
│ 📊 Complexity: High │
|
|
688
|
+
│ ⏱️ Estimated: 6 hours │
|
|
689
|
+
│ 🎯 Phase: 2 - Core Features │
|
|
690
|
+
│ 👤 Assigned to you │
|
|
691
|
+
│ 🌿 Branch: feature/T2.1-implement-login-api │
|
|
692
|
+
│ 📋 Issue: #42 (open) │
|
|
693
|
+
│ 🔀 PR: #45 (awaiting review) │
|
|
694
|
+
│ │
|
|
695
|
+
│ ✅ All dependencies completed │
|
|
696
|
+
│ │
|
|
697
|
+
│ ── Why This Task? ──────────────────────────────────────────────────────── │
|
|
698
|
+
│ │
|
|
699
|
+
│ • PR is awaiting review - finish the review cycle! │
|
|
700
|
+
│ • This task is assigned to you │
|
|
701
|
+
│ • Unlocks 3 other tasks │
|
|
702
|
+
│ │
|
|
703
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
704
|
+
│ │
|
|
705
|
+
│ 💡 Continue working: │
|
|
706
|
+
│ • git checkout feature/T2.1-implement-login-api │
|
|
707
|
+
│ • Address PR review comments │
|
|
708
|
+
│ │
|
|
709
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
**Example output (English - Assigned to current user):**
|
|
713
|
+
```
|
|
714
|
+
🎯 Recommended Next Task
|
|
715
|
+
|
|
716
|
+
T2.1: API Endpoints
|
|
717
|
+
|
|
718
|
+
Complexity: Medium
|
|
719
|
+
Estimated: 5 hours
|
|
720
|
+
Phase: 2 - Core Features
|
|
721
|
+
👤 Assigned to you
|
|
722
|
+
|
|
723
|
+
✅ All dependencies completed
|
|
724
|
+
|
|
725
|
+
🎯 Why this task?
|
|
726
|
+
• Unlocks 3 other tasks
|
|
727
|
+
• Critical for Phase 2 progress
|
|
728
|
+
• This task is assigned to you - ready to work on!
|
|
729
|
+
|
|
730
|
+
📝 Task Details:
|
|
731
|
+
Implement REST API endpoints for user management...
|
|
732
|
+
|
|
733
|
+
Ready to start?
|
|
734
|
+
/planUpdate T2.1 start
|
|
735
|
+
|
|
736
|
+
────────────────────────────────────────────────────────────
|
|
737
|
+
|
|
738
|
+
💡 Alternative Tasks (if this doesn't fit):
|
|
739
|
+
|
|
740
|
+
1. T2.2: Data Validation - Low - 2 hours
|
|
741
|
+
2. T2.3: Error Handling - Medium - 3 hours 👤 bob@company.com
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
**Example output (English - Assigned to someone else):**
|
|
745
|
+
```
|
|
746
|
+
🎯 Recommended Next Task
|
|
747
|
+
|
|
748
|
+
T2.3: Error Handling
|
|
749
|
+
|
|
750
|
+
Complexity: Medium
|
|
751
|
+
Estimated: 3 hours
|
|
752
|
+
Phase: 2 - Core Features
|
|
753
|
+
👤 Assigned to: Jane Smith
|
|
754
|
+
|
|
755
|
+
✅ All dependencies completed
|
|
756
|
+
|
|
757
|
+
🎯 Why this task?
|
|
758
|
+
• Unlocks 2 other tasks
|
|
759
|
+
• This task is already assigned. Consider picking an unassigned task.
|
|
760
|
+
|
|
761
|
+
📝 Task Details:
|
|
762
|
+
Implement global error handling middleware...
|
|
763
|
+
|
|
764
|
+
Ready to start?
|
|
765
|
+
/planUpdate T2.3 start
|
|
766
|
+
|
|
767
|
+
────────────────────────────────────────────────────────────
|
|
768
|
+
|
|
769
|
+
💡 Alternative Tasks (if this doesn't fit):
|
|
770
|
+
|
|
771
|
+
1. T2.4: Logging Setup - Low - 2 hours
|
|
772
|
+
2. T2.5: Rate Limiting - Medium - 4 hours 👤 (you)
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
**Example output (Georgian):**
|
|
776
|
+
```
|
|
777
|
+
🎯 რეკომენდებული შემდეგი ამოცანა
|
|
778
|
+
|
|
779
|
+
T1.2: მონაცემთა ბაზის დაყენება
|
|
780
|
+
|
|
781
|
+
სირთულე: საშუალო
|
|
782
|
+
შეფასებული: 4 საათი
|
|
783
|
+
ეტაპი: 1 - საფუძველი
|
|
784
|
+
👤 დაუნიშნავი
|
|
785
|
+
|
|
786
|
+
✅ ყველა დამოკიდებულება დასრულდა
|
|
787
|
+
|
|
788
|
+
🎯 რატომ ეს ამოცანა?
|
|
789
|
+
• ხსნის 3 სხვა ამოცანას
|
|
790
|
+
• კრიტიკული მე-2 ეტაპის პროგრესისთვის
|
|
791
|
+
• კარგი სირთულის ბალანსი წინა ამოცანის შემდეგ
|
|
792
|
+
|
|
793
|
+
📝 ამოცანის დეტალები:
|
|
794
|
+
PostgreSQL-ის დაყენება connection pooling-ით
|
|
795
|
+
და საწყისი სქემის დაყენებით...
|
|
796
|
+
|
|
797
|
+
მზად ხართ დასაწყებად?
|
|
798
|
+
/planUpdate T1.2 start
|
|
799
|
+
|
|
800
|
+
────────────────────────────────────────────────────────────
|
|
801
|
+
|
|
802
|
+
💡 ალტერნატიული ამოცანები (თუ ეს არ გიხდებათ):
|
|
803
|
+
|
|
804
|
+
1. T1.3: ავთენტიფიკაციის დაყენება - მაღალი - 6 საათი
|
|
805
|
+
2. T2.1: API Endpoints - საშუალო - 5 საათი 👤 jane@company.com
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
**Instructions for Claude:**
|
|
809
|
+
|
|
810
|
+
Use translation keys for all output:
|
|
811
|
+
- Title: `t.commands.next.title`
|
|
812
|
+
- Recommended task: `t.commands.next.recommendedTask`
|
|
813
|
+
- Complexity: `t.commands.next.complexity` + `t.templates.complexity.{low/medium/high}`
|
|
814
|
+
- Estimated: `t.commands.next.estimated`
|
|
815
|
+
- Phase: `t.commands.next.phase`
|
|
816
|
+
- Dependencies: `t.commands.next.dependenciesCompleted`
|
|
817
|
+
- Why: `t.commands.next.whyThisTask`
|
|
818
|
+
- Details: `t.commands.next.taskDetails`
|
|
819
|
+
- Ready: `t.commands.next.readyToStart`
|
|
820
|
+
- Alternatives: `t.commands.next.alternatives`
|
|
821
|
+
|
|
822
|
+
**Assignee translation keys (v1.6.0+):**
|
|
823
|
+
- Assigned to: `t.commands.next.assignedTo` + assignee name
|
|
824
|
+
- Unassigned: `t.commands.next.unassigned`
|
|
825
|
+
- Assigned to you: `t.commands.next.assignedToYou`
|
|
826
|
+
- Assigned hint: `t.commands.next.assignedHint` (shown when task is assigned to someone else)
|
|
827
|
+
- You are assigned: `t.commands.next.youAreAssigned` (shown when task is assigned to current user)
|
|
828
|
+
|
|
829
|
+
**GitHub status translation keys (v1.6.0+ T13.6):**
|
|
830
|
+
- Branch: `t.commands.next.github.branch`
|
|
831
|
+
- Issue: `t.commands.next.github.issue`
|
|
832
|
+
- PR: `t.commands.next.github.pr`
|
|
833
|
+
- Open: `t.commands.next.github.open`
|
|
834
|
+
- Closed: `t.commands.next.github.closed`
|
|
835
|
+
- Merged: `t.commands.next.github.merged`
|
|
836
|
+
- Approved: `t.commands.next.github.approved`
|
|
837
|
+
- Changes Requested: `t.commands.next.github.changesRequested`
|
|
838
|
+
- Awaiting Review: `t.commands.next.github.awaitingReview`
|
|
839
|
+
- No activity: `t.commands.next.github.noActivity`
|
|
840
|
+
- Create branch hint: `t.commands.next.github.createBranchHint`
|
|
841
|
+
- Continue working: `t.commands.next.github.continueWorking`
|
|
842
|
+
- PR awaiting hint: `t.commands.next.github.prAwaitingHint`
|
|
843
|
+
|
|
844
|
+
### Step 7: Handle Special Cases
|
|
845
|
+
|
|
846
|
+
#### Case 1: No Available Tasks (All Blocked or Waiting)
|
|
847
|
+
|
|
848
|
+
**Pseudo-code:**
|
|
849
|
+
```javascript
|
|
850
|
+
let output = t.commands.next.noTasks + "\n\n"
|
|
851
|
+
output += t.commands.next.projectStatus + "\n"
|
|
852
|
+
output += t.commands.next.completed + " " + completedCount + "/" + totalCount + "\n"
|
|
853
|
+
output += t.commands.next.inProgress + " " + inProgressCount + "\n"
|
|
854
|
+
output += t.commands.next.blocked + " " + blockedCount + "\n"
|
|
855
|
+
output += t.commands.next.waitingOnDeps + " " + waitingCount + "\n\n"
|
|
856
|
+
|
|
857
|
+
if (inProgressTasks.length > 0) {
|
|
858
|
+
output += t.commands.next.tasksInProgress + "\n"
|
|
859
|
+
output += inProgressTasks.map(t => ` ${t.id}: ${t.name}`).join("\n") + "\n\n"
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
if (blockedTasks.length > 0) {
|
|
863
|
+
output += t.commands.next.blockedTasks + "\n"
|
|
864
|
+
output += blockedTasks.map(t => ` ${t.id}: ${t.name}`).join("\n") + "\n\n"
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
output += t.commands.next.suggestedActions + "\n"
|
|
868
|
+
output += "1. " + t.commands.next.completeInProgress + "\n"
|
|
869
|
+
output += "2. " + t.commands.next.resolveBlockers + "\n"
|
|
870
|
+
output += "3. " + t.commands.next.reviewDependencies
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
**Example output (English):**
|
|
874
|
+
|
|
875
|
+
```
|
|
876
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
877
|
+
│ ⚠️ No Tasks Available │
|
|
878
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
879
|
+
│ │
|
|
880
|
+
│ No tasks currently available to work on. │
|
|
881
|
+
│ │
|
|
882
|
+
│ ── Project Status ──────────────────────────────────────────────────────── │
|
|
883
|
+
│ │
|
|
884
|
+
│ ✅ Completed: 5/18 │
|
|
885
|
+
│ 🔄 In Progress: 2 │
|
|
886
|
+
│ 🚫 Blocked: 1 │
|
|
887
|
+
│ ⏳ Waiting on Dependencies: 10 │
|
|
888
|
+
│ │
|
|
889
|
+
│ ── Tasks In Progress ───────────────────────────────────────────────────── │
|
|
890
|
+
│ │
|
|
891
|
+
│ • T1.2: Database Setup │
|
|
892
|
+
│ • T1.3: Authentication │
|
|
893
|
+
│ │
|
|
894
|
+
│ ── Blocked Tasks ───────────────────────────────────────────────────────── │
|
|
895
|
+
│ │
|
|
896
|
+
│ • T2.1: API Endpoints (waiting on design) │
|
|
897
|
+
│ │
|
|
898
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
899
|
+
│ │
|
|
900
|
+
│ 💡 Suggested Actions: │
|
|
901
|
+
│ 1. Complete in-progress tasks │
|
|
902
|
+
│ 2. Resolve blockers on blocked tasks │
|
|
903
|
+
│ 3. Review dependencies if tasks seem stuck │
|
|
904
|
+
│ │
|
|
905
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
**Instructions for Claude:**
|
|
909
|
+
|
|
910
|
+
Use translation keys:
|
|
911
|
+
- `t.commands.next.noTasks`
|
|
912
|
+
- `t.commands.next.projectStatus`
|
|
913
|
+
- `t.commands.next.completed`
|
|
914
|
+
- `t.commands.next.inProgress`
|
|
915
|
+
- `t.commands.next.blocked`
|
|
916
|
+
- `t.commands.next.waitingOnDeps`
|
|
917
|
+
- `t.commands.next.tasksInProgress`
|
|
918
|
+
- `t.commands.next.blockedTasks`
|
|
919
|
+
- `t.commands.next.suggestedActions`
|
|
920
|
+
- `t.commands.next.completeInProgress`
|
|
921
|
+
- `t.commands.next.resolveBlockers`
|
|
922
|
+
- `t.commands.next.reviewDependencies`
|
|
923
|
+
|
|
924
|
+
#### Case 2: All Tasks Complete
|
|
925
|
+
|
|
926
|
+
**Pseudo-code:**
|
|
927
|
+
```javascript
|
|
928
|
+
let output = t.commands.next.allComplete + "\n\n"
|
|
929
|
+
output += t.commands.next.projectComplete + "\n\n"
|
|
930
|
+
output += t.commands.next.whatsNext + "\n"
|
|
931
|
+
output += t.commands.next.deploy + "\n"
|
|
932
|
+
output += t.commands.next.postMortem + "\n"
|
|
933
|
+
output += t.commands.next.gatherFeedback + "\n"
|
|
934
|
+
output += t.commands.next.planNextVersion + "\n"
|
|
935
|
+
output += t.commands.next.celebrate + "\n\n"
|
|
936
|
+
output += t.commands.next.greatWork
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
**Example output (English):**
|
|
940
|
+
|
|
941
|
+
```
|
|
942
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
943
|
+
│ 🎉 PROJECT COMPLETE │
|
|
944
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
945
|
+
│ │
|
|
946
|
+
│ Congratulations! All tasks are complete! │
|
|
947
|
+
│ │
|
|
948
|
+
│ ── Project Summary ─────────────────────────────────────────────────────── │
|
|
949
|
+
│ │
|
|
950
|
+
│ ✅ Project: [PROJECT_NAME] │
|
|
951
|
+
│ 📊 Progress: ████████████████████████████████ 100% │
|
|
952
|
+
│ 🏆 Tasks: [Total] completed across [N] phases │
|
|
953
|
+
│ │
|
|
954
|
+
│ ╭────────────────────────────────────────────────────────────────────────╮ │
|
|
955
|
+
│ │ ✨ Project Status: COMPLETE │ │
|
|
956
|
+
│ ╰────────────────────────────────────────────────────────────────────────╯ │
|
|
957
|
+
│ │
|
|
958
|
+
│ ── What's Next? ────────────────────────────────────────────────────────── │
|
|
959
|
+
│ │
|
|
960
|
+
│ • Deploy to production (if not already) │
|
|
961
|
+
│ • Write post-mortem / lessons learned │
|
|
962
|
+
│ • Gather user feedback │
|
|
963
|
+
│ • Plan next version/features │
|
|
964
|
+
│ • Celebrate your success! 🎊 │
|
|
965
|
+
│ │
|
|
966
|
+
│ Great work on completing this project! 🚀 │
|
|
967
|
+
│ │
|
|
968
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
969
|
+
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
#### Case 3: Only High-Complexity Tasks Left
|
|
973
|
+
|
|
974
|
+
```
|
|
975
|
+
🎯 Recommended Next Task
|
|
976
|
+
|
|
977
|
+
╔══════════════════════════════════════════════════════════╗
|
|
978
|
+
║ T[X].[Y]: [Task Name] ║
|
|
979
|
+
║ 📊 Complexity: High ⚠️ ║
|
|
980
|
+
║ ⏱️ Estimated: [X] hours ║
|
|
981
|
+
╚══════════════════════════════════════════════════════════╝
|
|
982
|
+
|
|
983
|
+
⚠️ Note: This is a complex task. Consider:
|
|
984
|
+
• Breaking it down into subtasks
|
|
985
|
+
• Setting aside focused time
|
|
986
|
+
• Getting help if needed
|
|
987
|
+
• Taking breaks during implementation
|
|
988
|
+
|
|
989
|
+
[Rest of normal recommendation]
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
#### Case 4: Many In-Progress Tasks
|
|
993
|
+
|
|
994
|
+
If 3+ tasks are IN_PROGRESS:
|
|
995
|
+
|
|
996
|
+
```
|
|
997
|
+
⚠️ You have [N] tasks in progress.
|
|
998
|
+
|
|
999
|
+
💡 Tip: Consider finishing in-progress tasks before starting new ones:
|
|
1000
|
+
|
|
1001
|
+
🔄 In Progress:
|
|
1002
|
+
1. T[X].[Y]: [Name] ([Complexity])
|
|
1003
|
+
2. T[A].[B]: [Name] ([Complexity])
|
|
1004
|
+
3. T[C].[D]: [Name] ([Complexity])
|
|
1005
|
+
|
|
1006
|
+
Benefits of finishing first:
|
|
1007
|
+
• Clear sense of progress
|
|
1008
|
+
• Unlock dependent tasks
|
|
1009
|
+
• Maintain focus and momentum
|
|
1010
|
+
• Avoid context switching
|
|
1011
|
+
|
|
1012
|
+
────────────────────────────────────────────────────────────
|
|
1013
|
+
|
|
1014
|
+
Still want to start something new? Here's the recommendation:
|
|
1015
|
+
[Normal recommendation follows]
|
|
1016
|
+
```
|
|
1017
|
+
|
|
1018
|
+
### Step 8: Consider Context
|
|
1019
|
+
|
|
1020
|
+
Provide context-aware advice based on project state:
|
|
1021
|
+
|
|
1022
|
+
#### Early in Project (< 25% complete)
|
|
1023
|
+
```
|
|
1024
|
+
🌟 Early Stage Tips:
|
|
1025
|
+
• Focus on foundation tasks
|
|
1026
|
+
• Don't skip setup steps
|
|
1027
|
+
• Document as you go
|
|
1028
|
+
• Test early and often
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
#### Mid Project (25-75% complete)
|
|
1032
|
+
```
|
|
1033
|
+
🚀 Building Momentum:
|
|
1034
|
+
• You're making great progress!
|
|
1035
|
+
• Keep quality high
|
|
1036
|
+
• Watch for scope creep
|
|
1037
|
+
• Refactor if needed
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
#### Late Project (> 75% complete)
|
|
1041
|
+
```
|
|
1042
|
+
🏁 Final Sprint:
|
|
1043
|
+
• Almost there!
|
|
1044
|
+
• Don't rush quality
|
|
1045
|
+
• Test thoroughly
|
|
1046
|
+
• Update documentation
|
|
1047
|
+
• Plan deployment
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
## Reasoning Examples
|
|
1051
|
+
|
|
1052
|
+
### Example 1: Dependency Unlock
|
|
1053
|
+
|
|
1054
|
+
```
|
|
1055
|
+
🎯 Why this task?
|
|
1056
|
+
• Unlocks 3 other tasks (T2.2, T2.3, T2.4)
|
|
1057
|
+
• Critical path item - other work depends on this
|
|
1058
|
+
• Completing this opens up parallel work opportunities
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
### Example 2: Complexity Balance
|
|
1062
|
+
|
|
1063
|
+
```
|
|
1064
|
+
🎯 Why this task?
|
|
1065
|
+
• Medium complexity - good after completing complex T1.3
|
|
1066
|
+
• Prevents burnout with more manageable scope
|
|
1067
|
+
• Maintains momentum without overwhelming difficulty
|
|
1068
|
+
```
|
|
1069
|
+
|
|
1070
|
+
### Example 3: Phase Progression
|
|
1071
|
+
|
|
1072
|
+
```
|
|
1073
|
+
🎯 Why this task?
|
|
1074
|
+
• Last task in Phase 1 - completes foundation
|
|
1075
|
+
• Allows moving to Phase 2 (core features)
|
|
1076
|
+
• Natural progression point in project
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
### Example 4: Quick Win
|
|
1080
|
+
|
|
1081
|
+
```
|
|
1082
|
+
🎯 Why this task?
|
|
1083
|
+
• Low complexity - quick win opportunity
|
|
1084
|
+
• Boosts progress percentage significantly
|
|
1085
|
+
• Good for maintaining motivation
|
|
1086
|
+
• Easy to fit into short work session
|
|
1087
|
+
```
|
|
1088
|
+
|
|
1089
|
+
## Algorithms
|
|
1090
|
+
|
|
1091
|
+
### Finding Dependent Tasks
|
|
1092
|
+
|
|
1093
|
+
For a given task TX.Y, find tasks that list it in dependencies:
|
|
1094
|
+
|
|
1095
|
+
```
|
|
1096
|
+
For each task T:
|
|
1097
|
+
If T.dependencies contains TX.Y:
|
|
1098
|
+
Add T to dependents list
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
Count these to determine "unlock value".
|
|
1102
|
+
|
|
1103
|
+
### Checking Dependency Satisfaction
|
|
1104
|
+
|
|
1105
|
+
For a task to be available, check each dependency:
|
|
1106
|
+
|
|
1107
|
+
```
|
|
1108
|
+
For each dependency D in task.dependencies:
|
|
1109
|
+
Find task with ID = D
|
|
1110
|
+
If task.status != DONE:
|
|
1111
|
+
Return False (not satisfied)
|
|
1112
|
+
Return True (all satisfied)
|
|
1113
|
+
```
|
|
1114
|
+
|
|
1115
|
+
### Phase Detection
|
|
1116
|
+
|
|
1117
|
+
```
|
|
1118
|
+
Extract phase number from task ID:
|
|
1119
|
+
T1.1 → Phase 1
|
|
1120
|
+
T2.3 → Phase 2
|
|
1121
|
+
T15.7 → Phase 15
|
|
1122
|
+
|
|
1123
|
+
Find current phase:
|
|
1124
|
+
For phase in [1, 2, 3, 4, ...]:
|
|
1125
|
+
If any task in phase is not DONE:
|
|
1126
|
+
Return phase
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
## Edge Cases
|
|
1130
|
+
|
|
1131
|
+
1. **Circular Dependencies**: Detect and warn user
|
|
1132
|
+
```
|
|
1133
|
+
⚠️ Warning: Circular dependency detected between T2.1 and T2.3
|
|
1134
|
+
Please review and fix the dependencies in PROJECT_PLAN.md
|
|
1135
|
+
```
|
|
1136
|
+
|
|
1137
|
+
2. **Missing Dependencies**: Task references non-existent task
|
|
1138
|
+
```
|
|
1139
|
+
⚠️ Warning: Task T2.3 depends on T1.5, which doesn't exist
|
|
1140
|
+
Treating as satisfied for now.
|
|
1141
|
+
```
|
|
1142
|
+
|
|
1143
|
+
3. **Empty Plan**: No tasks defined
|
|
1144
|
+
```
|
|
1145
|
+
⚠️ No tasks found in PROJECT_PLAN.md
|
|
1146
|
+
Please add tasks to the "Tasks & Implementation Plan" section.
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
## Output Formatting
|
|
1150
|
+
|
|
1151
|
+
Use visual elements for clarity:
|
|
1152
|
+
- ✅ Checkmarks for completed items
|
|
1153
|
+
- 🔄 In progress indicator
|
|
1154
|
+
- 🚫 Blocked indicator
|
|
1155
|
+
- 📊 Complexity indicator
|
|
1156
|
+
- ⏱️ Time estimate
|
|
1157
|
+
- 🎯 Goal/recommendation
|
|
1158
|
+
- 💡 Tips and suggestions
|
|
1159
|
+
- ⚠️ Warnings
|
|
1160
|
+
- 🎉 Celebrations
|
|
1161
|
+
|
|
1162
|
+
Keep output scannable and actionable.
|
|
1163
|
+
|
|
1164
|
+
## Success Criteria
|
|
1165
|
+
|
|
1166
|
+
A good recommendation should:
|
|
1167
|
+
- ✅ Consider all relevant factors (dependencies, phase, complexity)
|
|
1168
|
+
- ✅ Provide clear reasoning
|
|
1169
|
+
- ✅ Show task details
|
|
1170
|
+
- ✅ Offer alternatives
|
|
1171
|
+
- ✅ Give actionable next steps
|
|
1172
|
+
- ✅ Be contextually aware
|
|
1173
|
+
- ✅ Help maintain project momentum
|
|
1174
|
+
- ✅ Show assignee information when connected to cloud (v1.6.0+)
|
|
1175
|
+
- ✅ Indicate if task is assigned to current user or someone else
|
|
1176
|
+
- ✅ Gracefully degrade when not authenticated (no assignee info shown)
|
|
1177
|
+
- ✅ Show GitHub status when GitHub is integrated (v1.6.0+ T13.6)
|
|
1178
|
+
- ✅ Display branch name if created for the task
|
|
1179
|
+
- ✅ Display linked GitHub issue number and state
|
|
1180
|
+
- ✅ Display linked PR number, state, and review status
|
|
1181
|
+
- ✅ Provide GitHub-aware hints (create branch, address PR comments)
|
|
1182
|
+
- ✅ Show compact GitHub info in alternatives list
|
|
1183
|
+
- ✅ Gracefully degrade when GitHub is not integrated
|
|
1184
|
+
|
|
1185
|
+
## Implementation Notes
|
|
1186
|
+
|
|
1187
|
+
1. **Parse carefully**: Use regex or string matching to extract task details
|
|
1188
|
+
2. **Handle variations**: Tasks may have slightly different formatting
|
|
1189
|
+
3. **Be robust**: Don't fail on minor formatting issues
|
|
1190
|
+
4. **Calculate accurately**: Ensure dependency logic is correct
|
|
1191
|
+
5. **Explain well**: Users should understand WHY this task is recommended
|
|
1192
|
+
6. **Stay positive**: Encourage users and maintain motivation
|
|
1193
|
+
7. **Fetch assignments gracefully (v1.6.0+)**: Only fetch when authenticated and linked; use short timeouts; continue without assignments if fetch fails
|
|
1194
|
+
8. **Show assignee context**: Help users understand who is working on what to avoid conflicts
|
|
1195
|
+
9. **Prioritize unassigned tasks**: When recommending, consider that unassigned tasks may be better choices for the user
|
|
1196
|
+
10. **Fetch GitHub status gracefully (v1.6.0+ T13.6)**: Check GitHub integration first; use short timeouts; fallback to local git branch detection if cloud unavailable
|
|
1197
|
+
11. **Provide GitHub-aware hints**: When a task has a branch, suggest checkout; when PR exists, suggest addressing reviews; when no activity, suggest creating a branch
|
|
1198
|
+
12. **Show compact GitHub info in alternatives**: Use icons (🌿, 🔀, ✅, ⚠️) to indicate GitHub status without overwhelming the list
|
|
1199
|
+
|
|
1200
|
+
This command is about **intelligent guidance**, not just listing tasks!
|