planflow-plugin 0.1.1 → 0.1.3
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/commands/pfCloudList/SKILL.md +28 -3
- package/commands/pfCloudNew/SKILL.md +79 -4
- package/commands/pfSyncPush/SKILL.md +177 -8
- package/commands/pfTeamInvite/SKILL.md +5 -5
- package/commands/pfTeamRole/SKILL.md +6 -6
- package/commands/planFormatCheck/SKILL.md +346 -0
- package/commands/planSpec/SKILL.md +93 -31
- package/package.json +1 -1
|
@@ -61,7 +61,32 @@ If not authenticated, display error card:
|
|
|
61
61
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
## Step 2: Fetch
|
|
64
|
+
## Step 2: Fetch User's Organizations
|
|
65
|
+
|
|
66
|
+
First, fetch the user's organizations to get the default organization ID:
|
|
67
|
+
|
|
68
|
+
**API Call:**
|
|
69
|
+
```bash
|
|
70
|
+
curl -s \
|
|
71
|
+
-H "Authorization: Bearer {TOKEN}" \
|
|
72
|
+
"https://api.planflow.tools/organizations"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Response:**
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"success": true,
|
|
79
|
+
"data": {
|
|
80
|
+
"organizations": [
|
|
81
|
+
{ "id": "org-uuid", "name": "My Org", "role": "owner" }
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Use the first organization with `owner` role, or fall back to the first organization.
|
|
88
|
+
|
|
89
|
+
## Step 3: Fetch Projects (with Loading)
|
|
65
90
|
|
|
66
91
|
**Loading Card:**
|
|
67
92
|
|
|
@@ -79,10 +104,10 @@ If not authenticated, display error card:
|
|
|
79
104
|
```bash
|
|
80
105
|
curl -s \
|
|
81
106
|
-H "Authorization: Bearer {TOKEN}" \
|
|
82
|
-
"https://api.planflow.tools/projects"
|
|
107
|
+
"https://api.planflow.tools/projects?organizationId={ORG_ID}"
|
|
83
108
|
```
|
|
84
109
|
|
|
85
|
-
## Step
|
|
110
|
+
## Step 4: Display Projects Card
|
|
86
111
|
|
|
87
112
|
```
|
|
88
113
|
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
@@ -88,7 +88,81 @@ If not authenticated, display error card:
|
|
|
88
88
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
## Step 4:
|
|
91
|
+
## Step 4: Fetch User's Organizations
|
|
92
|
+
|
|
93
|
+
**API Call:**
|
|
94
|
+
```bash
|
|
95
|
+
curl -s -X GET \
|
|
96
|
+
-H "Authorization: Bearer {TOKEN}" \
|
|
97
|
+
"https://api.planflow.tools/organizations"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Response:**
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"success": true,
|
|
104
|
+
"data": {
|
|
105
|
+
"organizations": [
|
|
106
|
+
{
|
|
107
|
+
"id": "org-uuid-1",
|
|
108
|
+
"name": "My Company",
|
|
109
|
+
"slug": "my-company",
|
|
110
|
+
"role": "owner"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"id": "org-uuid-2",
|
|
114
|
+
"name": "Personal",
|
|
115
|
+
"slug": "personal",
|
|
116
|
+
"role": "owner"
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Step 5: Select or Create Organization
|
|
124
|
+
|
|
125
|
+
**If user has NO organizations:**
|
|
126
|
+
|
|
127
|
+
Create a "Personal" organization first:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
curl -s -X POST \
|
|
131
|
+
-H "Content-Type: application/json" \
|
|
132
|
+
-H "Authorization: Bearer {TOKEN}" \
|
|
133
|
+
-d '{"name": "Personal", "slug": "personal"}' \
|
|
134
|
+
"https://api.planflow.tools/organizations"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Then use the returned `organization.id` as `organizationId`.
|
|
138
|
+
|
|
139
|
+
**If user has ONE organization:**
|
|
140
|
+
|
|
141
|
+
Use that organization's `id` as `organizationId` automatically.
|
|
142
|
+
|
|
143
|
+
**If user has MULTIPLE organizations:**
|
|
144
|
+
|
|
145
|
+
Ask user to select which organization to create the project in:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
149
|
+
│ ☁️ Select Organization │
|
|
150
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
151
|
+
│ │
|
|
152
|
+
│ Which organization should this project belong to? │
|
|
153
|
+
│ │
|
|
154
|
+
│ 1. My Company (owner) │
|
|
155
|
+
│ 2. Personal (owner) │
|
|
156
|
+
│ 3. Team Alpha (editor) │
|
|
157
|
+
│ │
|
|
158
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Use the `AskUserQuestion` tool to let the user choose.
|
|
162
|
+
|
|
163
|
+
**NOTE:** Only organizations where user has `owner`, `admin`, or `editor` role can be used to create projects. Filter out organizations where user has `viewer` role.
|
|
164
|
+
|
|
165
|
+
## Step 6: Show Creation Card
|
|
92
166
|
|
|
93
167
|
```
|
|
94
168
|
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
@@ -98,6 +172,7 @@ If not authenticated, display error card:
|
|
|
98
172
|
│ ⠹ Creating project on cloud... │
|
|
99
173
|
│ │
|
|
100
174
|
│ Project name: {projectName} │
|
|
175
|
+
│ Organization: {organizationName} │
|
|
101
176
|
│ │
|
|
102
177
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
103
178
|
```
|
|
@@ -107,11 +182,11 @@ If not authenticated, display error card:
|
|
|
107
182
|
curl -s -X POST \
|
|
108
183
|
-H "Content-Type: application/json" \
|
|
109
184
|
-H "Authorization: Bearer {TOKEN}" \
|
|
110
|
-
-d '{"name": "Project Name"}' \
|
|
185
|
+
-d '{"name": "Project Name", "organizationId": "org-uuid"}' \
|
|
111
186
|
"https://api.planflow.tools/projects"
|
|
112
187
|
```
|
|
113
188
|
|
|
114
|
-
## Step
|
|
189
|
+
## Step 7: Link and Push
|
|
115
190
|
|
|
116
191
|
1. Link to new project (save projectId to config)
|
|
117
192
|
2. Push current plan
|
|
@@ -132,7 +207,7 @@ curl -s -X POST \
|
|
|
132
207
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
133
208
|
```
|
|
134
209
|
|
|
135
|
-
## Step
|
|
210
|
+
## Step 8: Show Success Card
|
|
136
211
|
|
|
137
212
|
```
|
|
138
213
|
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
@@ -193,22 +193,191 @@ echo "Tasks: $TASKS_COUNT, Completed: $COMPLETED_COUNT, Progress: $PROGRESS%"
|
|
|
193
193
|
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
-
**If tasksCount is 0 or null,
|
|
196
|
+
**If tasksCount is 0 or null, run automatic format validation (Step 3d):**
|
|
197
|
+
|
|
198
|
+
## Step 3d: Automatic Format Validation (if tasksCount is 0)
|
|
199
|
+
|
|
200
|
+
**CRITICAL: If no tasks were parsed, automatically validate and fix the format!**
|
|
201
|
+
|
|
202
|
+
When tasksCount is 0, you MUST:
|
|
203
|
+
|
|
204
|
+
1. **Read PROJECT_PLAN.md and scan for potential tasks**
|
|
205
|
+
2. **Check for common format issues**
|
|
206
|
+
3. **Offer to auto-fix if fixable**
|
|
207
|
+
|
|
208
|
+
### Format Detection Logic
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
// Read the plan content
|
|
212
|
+
const planContent = readFile("PROJECT_PLAN.md")
|
|
213
|
+
|
|
214
|
+
// Check for tasks in various formats
|
|
215
|
+
const validHeaderFormat = /^#{2,4}\s*\*{0,2}T\d+[A-Za-z]?\.\d+\*{0,2}[:\s]+.+/gm
|
|
216
|
+
const validTableFormat = /\|\s*T\d+[A-Za-z]?\.\d+\s*\|/g
|
|
217
|
+
|
|
218
|
+
// Check for INVALID formats (common mistakes)
|
|
219
|
+
const wrongFormat1 = /^[-*]\s*T\d+[A-Za-z]?\.\d+[:\s]+.+/gm // Bullet list format
|
|
220
|
+
const wrongFormat2 = /^\d+\.\s*T\d+[A-Za-z]?\.\d+[:\s]+.+/gm // Numbered list format
|
|
221
|
+
const wrongFormat3 = /^T\d+[A-Za-z]?\.\d+[:\s]+.+/gm // No header prefix
|
|
222
|
+
|
|
223
|
+
const validTasks = (planContent.match(validHeaderFormat) || []).length +
|
|
224
|
+
(planContent.match(validTableFormat) || []).length
|
|
225
|
+
const invalidTasks = (planContent.match(wrongFormat1) || []).length +
|
|
226
|
+
(planContent.match(wrongFormat2) || []).length +
|
|
227
|
+
(planContent.match(wrongFormat3) || []).length
|
|
228
|
+
|
|
229
|
+
if (invalidTasks > 0 && validTasks === 0) {
|
|
230
|
+
// Tasks exist but in wrong format - offer to fix
|
|
231
|
+
showFormatFixCard()
|
|
232
|
+
} else if (validTasks === 0 && invalidTasks === 0) {
|
|
233
|
+
// No tasks at all
|
|
234
|
+
showNoTasksCard()
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### If wrong format detected, show fix offer card:
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
242
|
+
│ ⚠️ FORMAT ISSUE DETECTED │
|
|
243
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
244
|
+
│ │
|
|
245
|
+
│ Found {invalidTasks} tasks in incorrect format. │
|
|
246
|
+
│ │
|
|
247
|
+
│ ── Current Format (incorrect) ───────────────────────────────────────── │
|
|
248
|
+
│ │
|
|
249
|
+
│ - T1.1: Task Name ❌ Bullet list not supported │
|
|
250
|
+
│ 1. T1.2: Another Task ❌ Numbered list not supported │
|
|
251
|
+
│ T1.3: Direct task ❌ Missing header prefix │
|
|
252
|
+
│ │
|
|
253
|
+
│ ── Required Format ──────────────────────────────────────────────────── │
|
|
254
|
+
│ │
|
|
255
|
+
│ #### T1.1: Task Name ✅ Header format │
|
|
256
|
+
│ - [ ] **Status**: TODO │
|
|
257
|
+
│ - **Complexity**: Low │
|
|
258
|
+
│ - **Dependencies**: None │
|
|
259
|
+
│ │
|
|
260
|
+
│ OR table format: │
|
|
261
|
+
│ | ID | Task | Complexity | Status | Dependencies | │
|
|
262
|
+
│ |-------|-----------|------------|--------|--------------| │
|
|
263
|
+
│ | T1.1 | Task Name | Low | TODO | - | │
|
|
264
|
+
│ │
|
|
265
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
266
|
+
│ │
|
|
267
|
+
│ 🔧 Would you like me to auto-fix the format? │
|
|
268
|
+
│ │
|
|
269
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Use AskUserQuestion:**
|
|
273
|
+
```javascript
|
|
274
|
+
AskUserQuestion({
|
|
275
|
+
questions: [{
|
|
276
|
+
question: "Would you like me to convert tasks to the correct format?",
|
|
277
|
+
header: "Fix Format",
|
|
278
|
+
multiSelect: false,
|
|
279
|
+
options: [
|
|
280
|
+
{
|
|
281
|
+
label: "Yes, auto-fix (Recommended)",
|
|
282
|
+
description: "Convert all tasks to header format and re-sync"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
label: "No, I'll fix manually",
|
|
286
|
+
description: "Keep current format, sync without tasks"
|
|
287
|
+
}
|
|
288
|
+
]
|
|
289
|
+
}]
|
|
290
|
+
})
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### If user chooses auto-fix:
|
|
294
|
+
|
|
295
|
+
**Convert tasks to correct format:**
|
|
296
|
+
|
|
297
|
+
```javascript
|
|
298
|
+
// Find all tasks in wrong format and convert
|
|
299
|
+
let fixedContent = planContent
|
|
300
|
+
|
|
301
|
+
// Convert bullet format: "- T1.1: Task" → "#### T1.1: Task\n- [ ] **Status**: TODO\n- **Complexity**: Medium\n- **Dependencies**: None"
|
|
302
|
+
fixedContent = fixedContent.replace(
|
|
303
|
+
/^[-*]\s*(T\d+[A-Za-z]?\.\d+)[:\s]+(.+)$/gm,
|
|
304
|
+
(match, taskId, taskName) => {
|
|
305
|
+
return `#### ${taskId}: ${taskName}
|
|
306
|
+
- [ ] **Status**: TODO
|
|
307
|
+
- **Complexity**: Medium
|
|
308
|
+
- **Dependencies**: None`
|
|
309
|
+
}
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
// Convert numbered format: "1. T1.1: Task" → header format
|
|
313
|
+
fixedContent = fixedContent.replace(
|
|
314
|
+
/^\d+\.\s*(T\d+[A-Za-z]?\.\d+)[:\s]+(.+)$/gm,
|
|
315
|
+
(match, taskId, taskName) => {
|
|
316
|
+
return `#### ${taskId}: ${taskName}
|
|
317
|
+
- [ ] **Status**: TODO
|
|
318
|
+
- **Complexity**: Medium
|
|
319
|
+
- **Dependencies**: None`
|
|
320
|
+
}
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
// Convert plain format: "T1.1: Task" → header format
|
|
324
|
+
fixedContent = fixedContent.replace(
|
|
325
|
+
/^(T\d+[A-Za-z]?\.\d+)[:\s]+(.+)$/gm,
|
|
326
|
+
(match, taskId, taskName) => {
|
|
327
|
+
return `#### ${taskId}: ${taskName}
|
|
328
|
+
- [ ] **Status**: TODO
|
|
329
|
+
- **Complexity**: Medium
|
|
330
|
+
- **Dependencies**: None`
|
|
331
|
+
}
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
// Write fixed content
|
|
335
|
+
writeFile("PROJECT_PLAN.md", fixedContent)
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**After fixing, re-push automatically:**
|
|
339
|
+
|
|
340
|
+
```
|
|
341
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
342
|
+
│ 🔧 FORMAT FIXED │
|
|
343
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
344
|
+
│ │
|
|
345
|
+
│ Converted {fixedCount} tasks to correct format. │
|
|
346
|
+
│ │
|
|
347
|
+
│ Re-syncing to cloud... │
|
|
348
|
+
│ │
|
|
349
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Then repeat Step 3b (API call) with the fixed content.
|
|
353
|
+
|
|
354
|
+
### If no tasks found at all:
|
|
197
355
|
|
|
198
356
|
```
|
|
199
357
|
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
200
|
-
│ ⚠️
|
|
358
|
+
│ ⚠️ NO TASKS FOUND │
|
|
201
359
|
├──────────────────────────────────────────────────────────────────────────────┤
|
|
202
360
|
│ │
|
|
203
|
-
│
|
|
361
|
+
│ The plan was synced but no tasks were detected. │
|
|
362
|
+
│ │
|
|
363
|
+
│ Your plan may be missing the Tasks section. │
|
|
364
|
+
│ │
|
|
365
|
+
│ ── Expected Task Format ─────────────────────────────────────────────── │
|
|
366
|
+
│ │
|
|
367
|
+
│ ## Tasks & Implementation Plan │
|
|
204
368
|
│ │
|
|
205
|
-
│
|
|
206
|
-
│
|
|
207
|
-
│
|
|
208
|
-
│
|
|
369
|
+
│ ### Phase 1: Foundation │
|
|
370
|
+
│ │
|
|
371
|
+
│ #### T1.1: Setup Project │
|
|
372
|
+
│ - [ ] **Status**: TODO │
|
|
373
|
+
│ - **Complexity**: Low │
|
|
374
|
+
│ - **Dependencies**: None │
|
|
375
|
+
│ │
|
|
376
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
209
377
|
│ │
|
|
210
378
|
│ 💡 {t.ui.labels.nextSteps} │
|
|
211
|
-
│ • /
|
|
379
|
+
│ • /planNew Create a new plan with tasks │
|
|
380
|
+
│ • Manually add tasks in the format shown above │
|
|
212
381
|
│ │
|
|
213
382
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
214
383
|
```
|
|
@@ -18,10 +18,11 @@ Send an invitation to add a new team member to the linked cloud project with inv
|
|
|
18
18
|
|
|
19
19
|
| Role | Permissions |
|
|
20
20
|
|------|-------------|
|
|
21
|
-
| `admin` | Full access, can manage team members |
|
|
22
21
|
| `editor` | Can edit tasks and plan (default) |
|
|
23
22
|
| `viewer` | Read-only access |
|
|
24
23
|
|
|
24
|
+
**Note:** Project-level invitations support `editor` and `viewer` roles. The `owner` role is automatically assigned to the project creator. For organization-level team management with `admin` role, use `/team` command.
|
|
25
|
+
|
|
25
26
|
## Step 0: Load Configuration
|
|
26
27
|
|
|
27
28
|
```javascript
|
|
@@ -53,14 +54,13 @@ const t = JSON.parse(readFile(`locales/${language}.json`))
|
|
|
53
54
|
│ │
|
|
54
55
|
│ ── Available Roles ───────────────────────────────────────────────────── │
|
|
55
56
|
│ │
|
|
56
|
-
│ admin - Full access, can manage team members │
|
|
57
57
|
│ editor - Can edit tasks and plan (default) │
|
|
58
58
|
│ viewer - Read-only access │
|
|
59
59
|
│ │
|
|
60
60
|
│ ── Examples ──────────────────────────────────────────────────────────── │
|
|
61
61
|
│ │
|
|
62
62
|
│ /pfTeamInvite alice@company.com │
|
|
63
|
-
│ /pfTeamInvite bob@company.com
|
|
63
|
+
│ /pfTeamInvite bob@company.com viewer │
|
|
64
64
|
│ │
|
|
65
65
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
66
66
|
```
|
|
@@ -141,7 +141,7 @@ const t = JSON.parse(readFile(`locales/${language}.json`))
|
|
|
141
141
|
│ alice@company.com is already part of this project. │
|
|
142
142
|
│ │
|
|
143
143
|
│ 💡 To change their role: │
|
|
144
|
-
│ • /pfTeamRole alice@company.com
|
|
144
|
+
│ • /pfTeamRole alice@company.com editor │
|
|
145
145
|
│ │
|
|
146
146
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
147
147
|
```
|
|
@@ -155,7 +155,7 @@ const t = JSON.parse(readFile(`locales/${language}.json`))
|
|
|
155
155
|
│ │
|
|
156
156
|
│ You don't have permission to invite team members. │
|
|
157
157
|
│ │
|
|
158
|
-
│ Only project owners
|
|
158
|
+
│ Only project owners can send invitations. │
|
|
159
159
|
│ │
|
|
160
160
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
161
161
|
```
|
|
@@ -12,17 +12,18 @@ Change the role of an existing team member in the linked cloud project with role
|
|
|
12
12
|
```bash
|
|
13
13
|
/pfTeamRole <email> <role> # Change member's role
|
|
14
14
|
/pfTeamRole bob@company.com viewer
|
|
15
|
-
/pfTeamRole alice@company.com
|
|
15
|
+
/pfTeamRole alice@company.com editor
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
## Available Roles
|
|
19
19
|
|
|
20
20
|
| Role | Permissions |
|
|
21
21
|
|------|-------------|
|
|
22
|
-
| `admin` | Full access, can manage team members |
|
|
23
22
|
| `editor` | Can edit tasks and plan |
|
|
24
23
|
| `viewer` | Read-only access |
|
|
25
24
|
|
|
25
|
+
**Note:** The `owner` role cannot be changed via this command. For organization-level roles (including `admin`), use `/team` command.
|
|
26
|
+
|
|
26
27
|
## Step 0: Load Configuration
|
|
27
28
|
|
|
28
29
|
```javascript
|
|
@@ -42,14 +43,13 @@ Change the role of an existing team member in the linked cloud project with role
|
|
|
42
43
|
│ │
|
|
43
44
|
│ ── Available Roles ───────────────────────────────────────────────────── │
|
|
44
45
|
│ │
|
|
45
|
-
│ admin - Full access, can manage team members │
|
|
46
46
|
│ editor - Can edit tasks and plan │
|
|
47
47
|
│ viewer - Read-only access │
|
|
48
48
|
│ │
|
|
49
49
|
│ ── Examples ──────────────────────────────────────────────────────────── │
|
|
50
50
|
│ │
|
|
51
51
|
│ /pfTeamRole bob@company.com viewer │
|
|
52
|
-
│ /pfTeamRole alice@company.com
|
|
52
|
+
│ /pfTeamRole alice@company.com editor │
|
|
53
53
|
│ │
|
|
54
54
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
55
55
|
```
|
|
@@ -95,7 +95,7 @@ Change the role of an existing team member in the linked cloud project with role
|
|
|
95
95
|
│ │
|
|
96
96
|
│ You cannot change your own role. │
|
|
97
97
|
│ │
|
|
98
|
-
│ Ask
|
|
98
|
+
│ Ask the project owner to change your role. │
|
|
99
99
|
│ │
|
|
100
100
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
101
101
|
```
|
|
@@ -139,7 +139,7 @@ Change the role of an existing team member in the linked cloud project with role
|
|
|
139
139
|
│ │
|
|
140
140
|
│ Invalid role: superadmin │
|
|
141
141
|
│ │
|
|
142
|
-
│ Valid roles:
|
|
142
|
+
│ Valid roles: editor, viewer │
|
|
143
143
|
│ │
|
|
144
144
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
145
145
|
```
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: planFormatCheck
|
|
3
|
+
description: Validate and fix PROJECT_PLAN.md task format
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Plan Format Check
|
|
7
|
+
|
|
8
|
+
Validate PROJECT_PLAN.md format and automatically fix any issues to ensure cloud sync compatibility.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
/planFormatCheck # Check format and show issues
|
|
14
|
+
/planFormatCheck --fix # Automatically fix format issues
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Step 0: Load Configuration
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
function getConfig() {
|
|
21
|
+
const localConfigPath = "./.plan-config.json"
|
|
22
|
+
let localConfig = {}
|
|
23
|
+
if (fileExists(localConfigPath)) {
|
|
24
|
+
try { localConfig = JSON.parse(readFile(localConfigPath)) } catch {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const globalConfigPath = expandPath("~/.config/claude/plan-plugin-config.json")
|
|
28
|
+
let globalConfig = {}
|
|
29
|
+
if (fileExists(globalConfigPath)) {
|
|
30
|
+
try { globalConfig = JSON.parse(readFile(globalConfigPath)) } catch {}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return { ...globalConfig, ...localConfig }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const config = getConfig()
|
|
37
|
+
const language = config.language || "en"
|
|
38
|
+
const t = JSON.parse(readFile(`locales/${language}.json`))
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Step 1: Parse Arguments
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
const args = commandArgs.trim().split(/\s+/)
|
|
45
|
+
const autoFix = args.includes("--fix")
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Step 2: Read and Analyze Plan
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
// Check if PROJECT_PLAN.md exists
|
|
52
|
+
if (!fileExists("PROJECT_PLAN.md")) {
|
|
53
|
+
showNoPlanCard()
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const planContent = readFile("PROJECT_PLAN.md")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Format Detection Patterns
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
// VALID formats (will be parsed by API)
|
|
64
|
+
const validHeaderPattern = /^#{2,4}\s*\*{0,2}(T\d+[A-Za-z]?\.\d+)\*{0,2}[:\s]+(.+)/gm
|
|
65
|
+
const validTablePattern = /\|\s*(T\d+[A-Za-z]?\.\d+)\s*\|/g
|
|
66
|
+
|
|
67
|
+
// INVALID formats (won't be parsed)
|
|
68
|
+
const bulletPattern = /^[-*]\s*(T\d+[A-Za-z]?\.\d+)[:\s]+(.+)/gm
|
|
69
|
+
const numberedPattern = /^\d+\.\s*(T\d+[A-Za-z]?\.\d+)[:\s]+(.+)/gm
|
|
70
|
+
const plainPattern = /^(T\d+[A-Za-z]?\.\d+)[:\s]+([^|\n]+)$/gm
|
|
71
|
+
|
|
72
|
+
// Count tasks in each format
|
|
73
|
+
const validHeaderTasks = [...planContent.matchAll(validHeaderPattern)]
|
|
74
|
+
const validTableTasks = [...planContent.matchAll(validTablePattern)]
|
|
75
|
+
const bulletTasks = [...planContent.matchAll(bulletPattern)]
|
|
76
|
+
const numberedTasks = [...planContent.matchAll(numberedPattern)]
|
|
77
|
+
const plainTasks = [...planContent.matchAll(plainPattern)]
|
|
78
|
+
|
|
79
|
+
const totalValid = validHeaderTasks.length + validTableTasks.length
|
|
80
|
+
const totalInvalid = bulletTasks.length + numberedTasks.length + plainTasks.length
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Step 3: Show Analysis Results
|
|
84
|
+
|
|
85
|
+
### All formats valid - success card:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
89
|
+
│ ✅ FORMAT CHECK PASSED │
|
|
90
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
91
|
+
│ │
|
|
92
|
+
│ Your PROJECT_PLAN.md format is correct! │
|
|
93
|
+
│ │
|
|
94
|
+
│ ── Task Summary ─────────────────────────────────────────────────────── │
|
|
95
|
+
│ │
|
|
96
|
+
│ 📊 Total tasks found: {totalValid} │
|
|
97
|
+
│ 📝 Header format: {validHeaderTasks.length} │
|
|
98
|
+
│ 📋 Table format: {validTableTasks.length} │
|
|
99
|
+
│ │
|
|
100
|
+
│ ── Format Details ───────────────────────────────────────────────────── │
|
|
101
|
+
│ │
|
|
102
|
+
│ ✅ All tasks use valid format │
|
|
103
|
+
│ ✅ Ready for cloud sync │
|
|
104
|
+
│ │
|
|
105
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
106
|
+
│ │
|
|
107
|
+
│ 💡 Next Steps: │
|
|
108
|
+
│ • /pfSyncPush Push to cloud │
|
|
109
|
+
│ │
|
|
110
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Issues found - warning card:
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
117
|
+
│ ⚠️ FORMAT ISSUES FOUND │
|
|
118
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
119
|
+
│ │
|
|
120
|
+
│ Found {totalInvalid} tasks in incorrect format. │
|
|
121
|
+
│ │
|
|
122
|
+
│ ── Current Status ───────────────────────────────────────────────────── │
|
|
123
|
+
│ │
|
|
124
|
+
│ ✅ Valid tasks: {totalValid} │
|
|
125
|
+
│ ❌ Invalid tasks: {totalInvalid} │
|
|
126
|
+
│ │
|
|
127
|
+
│ ── Issues Detected ──────────────────────────────────────────────────── │
|
|
128
|
+
│ │
|
|
129
|
+
│ {bulletTasks.length > 0 ? "• Bullet format (- T1.1: ...): " + bulletTasks.length + " tasks" : ""}
|
|
130
|
+
│ {numberedTasks.length > 0 ? "• Numbered format (1. T1.1: ...): " + numberedTasks.length + " tasks" : ""}
|
|
131
|
+
│ {plainTasks.length > 0 ? "• Plain format (T1.1: ...): " + plainTasks.length + " tasks" : ""}
|
|
132
|
+
│ │
|
|
133
|
+
│ ── Invalid Tasks ────────────────────────────────────────────────────── │
|
|
134
|
+
│ │
|
|
135
|
+
│ {Show first 5 invalid tasks as examples} │
|
|
136
|
+
│ │
|
|
137
|
+
│ ── Required Format ──────────────────────────────────────────────────── │
|
|
138
|
+
│ │
|
|
139
|
+
│ Header format: │
|
|
140
|
+
│ #### T1.1: Task Name │
|
|
141
|
+
│ - [ ] **Status**: TODO │
|
|
142
|
+
│ - **Complexity**: Low │
|
|
143
|
+
│ - **Dependencies**: None │
|
|
144
|
+
│ │
|
|
145
|
+
│ OR table format: │
|
|
146
|
+
│ | ID | Task | Complexity | Status | Deps | │
|
|
147
|
+
│ |------|-----------|------------|--------|------| │
|
|
148
|
+
│ | T1.1 | Task Name | Low | TODO | - | │
|
|
149
|
+
│ │
|
|
150
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
151
|
+
│ │
|
|
152
|
+
│ 💡 Next Steps: │
|
|
153
|
+
│ • /planFormatCheck --fix Auto-fix all issues │
|
|
154
|
+
│ • Fix manually using the format shown above │
|
|
155
|
+
│ │
|
|
156
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Step 4: Auto-Fix (if --fix flag)
|
|
160
|
+
|
|
161
|
+
If `--fix` flag is provided and there are invalid tasks:
|
|
162
|
+
|
|
163
|
+
### Convert all invalid formats to header format:
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
let fixedContent = planContent
|
|
167
|
+
let fixedCount = 0
|
|
168
|
+
|
|
169
|
+
// Convert bullet format: "- T1.1: Task" → header format
|
|
170
|
+
fixedContent = fixedContent.replace(
|
|
171
|
+
/^([-*])\s*(T\d+[A-Za-z]?\.\d+)[:\s]+(.+)$/gm,
|
|
172
|
+
(match, bullet, taskId, taskName) => {
|
|
173
|
+
fixedCount++
|
|
174
|
+
return `#### ${taskId}: ${taskName.trim()}
|
|
175
|
+
- [ ] **Status**: TODO
|
|
176
|
+
- **Complexity**: Medium
|
|
177
|
+
- **Dependencies**: None`
|
|
178
|
+
}
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
// Convert numbered format: "1. T1.1: Task" → header format
|
|
182
|
+
fixedContent = fixedContent.replace(
|
|
183
|
+
/^(\d+)\.\s*(T\d+[A-Za-z]?\.\d+)[:\s]+(.+)$/gm,
|
|
184
|
+
(match, num, taskId, taskName) => {
|
|
185
|
+
fixedCount++
|
|
186
|
+
return `#### ${taskId}: ${taskName.trim()}
|
|
187
|
+
- [ ] **Status**: TODO
|
|
188
|
+
- **Complexity**: Medium
|
|
189
|
+
- **Dependencies**: None`
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
// Convert plain format: "T1.1: Task" → header format (only at line start, not in tables)
|
|
194
|
+
fixedContent = fixedContent.replace(
|
|
195
|
+
/^(T\d+[A-Za-z]?\.\d+)[:\s]+([^|\n]+)$/gm,
|
|
196
|
+
(match, taskId, taskName) => {
|
|
197
|
+
// Skip if this looks like it might be part of a table (has | nearby)
|
|
198
|
+
if (taskName.includes('|')) return match
|
|
199
|
+
fixedCount++
|
|
200
|
+
return `#### ${taskId}: ${taskName.trim()}
|
|
201
|
+
- [ ] **Status**: TODO
|
|
202
|
+
- **Complexity**: Medium
|
|
203
|
+
- **Dependencies**: None`
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
// Write fixed content
|
|
208
|
+
writeFile("PROJECT_PLAN.md", fixedContent)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Show fix success card:
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
215
|
+
│ ✅ FORMAT FIXED │
|
|
216
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
217
|
+
│ │
|
|
218
|
+
│ Successfully converted {fixedCount} tasks to correct format! │
|
|
219
|
+
│ │
|
|
220
|
+
│ ── Changes Made ─────────────────────────────────────────────────────── │
|
|
221
|
+
│ │
|
|
222
|
+
│ • Converted bullet format tasks to header format │
|
|
223
|
+
│ • Converted numbered list tasks to header format │
|
|
224
|
+
│ • Converted plain format tasks to header format │
|
|
225
|
+
│ • Added Status, Complexity, and Dependencies fields │
|
|
226
|
+
│ │
|
|
227
|
+
│ ── Before → After ───────────────────────────────────────────────────── │
|
|
228
|
+
│ │
|
|
229
|
+
│ BEFORE: │
|
|
230
|
+
│ - T1.1: Setup project │
|
|
231
|
+
│ │
|
|
232
|
+
│ AFTER: │
|
|
233
|
+
│ #### T1.1: Setup project │
|
|
234
|
+
│ - [ ] **Status**: TODO │
|
|
235
|
+
│ - **Complexity**: Medium │
|
|
236
|
+
│ - **Dependencies**: None │
|
|
237
|
+
│ │
|
|
238
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
239
|
+
│ │
|
|
240
|
+
│ 💡 Next Steps: │
|
|
241
|
+
│ • Review the changes in PROJECT_PLAN.md │
|
|
242
|
+
│ • Update Status/Complexity/Dependencies as needed │
|
|
243
|
+
│ • /pfSyncPush Push to cloud │
|
|
244
|
+
│ │
|
|
245
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Error Handling
|
|
249
|
+
|
|
250
|
+
### No PROJECT_PLAN.md found:
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
254
|
+
│ ❌ ERROR │
|
|
255
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
256
|
+
│ │
|
|
257
|
+
│ No PROJECT_PLAN.md found in current directory. │
|
|
258
|
+
│ │
|
|
259
|
+
│ 💡 Next Steps: │
|
|
260
|
+
│ • /planNew Create a new project plan │
|
|
261
|
+
│ • cd to your project directory and try again │
|
|
262
|
+
│ │
|
|
263
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### No tasks found at all:
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
270
|
+
│ ⚠️ NO TASKS FOUND │
|
|
271
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
272
|
+
│ │
|
|
273
|
+
│ No tasks were found in PROJECT_PLAN.md. │
|
|
274
|
+
│ │
|
|
275
|
+
│ Your plan may be missing the Tasks section entirely. │
|
|
276
|
+
│ │
|
|
277
|
+
│ ── Add Tasks Using This Format ──────────────────────────────────────── │
|
|
278
|
+
│ │
|
|
279
|
+
│ ## Tasks & Implementation Plan │
|
|
280
|
+
│ │
|
|
281
|
+
│ ### Phase 1: Foundation │
|
|
282
|
+
│ │
|
|
283
|
+
│ #### T1.1: Setup Project │
|
|
284
|
+
│ - [ ] **Status**: TODO │
|
|
285
|
+
│ - **Complexity**: Low │
|
|
286
|
+
│ - **Dependencies**: None │
|
|
287
|
+
│ - **Description**: │
|
|
288
|
+
│ - Initialize the project structure │
|
|
289
|
+
│ - Configure development tools │
|
|
290
|
+
│ │
|
|
291
|
+
│ #### T1.2: Configure Database │
|
|
292
|
+
│ - [ ] **Status**: TODO │
|
|
293
|
+
│ - **Complexity**: Medium │
|
|
294
|
+
│ - **Dependencies**: T1.1 │
|
|
295
|
+
│ │
|
|
296
|
+
├──────────────────────────────────────────────────────────────────────────────┤
|
|
297
|
+
│ │
|
|
298
|
+
│ 💡 Next Steps: │
|
|
299
|
+
│ • /planNew Create a new plan with tasks │
|
|
300
|
+
│ • Add tasks manually in the format shown above │
|
|
301
|
+
│ │
|
|
302
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Valid Format Reference
|
|
306
|
+
|
|
307
|
+
### Header Format (Preferred)
|
|
308
|
+
|
|
309
|
+
```markdown
|
|
310
|
+
#### T1.1: Task Name
|
|
311
|
+
- [ ] **Status**: TODO
|
|
312
|
+
- **Complexity**: Low
|
|
313
|
+
- **Estimated**: 2 hours
|
|
314
|
+
- **Dependencies**: None
|
|
315
|
+
- **Description**:
|
|
316
|
+
- Detail 1
|
|
317
|
+
- Detail 2
|
|
318
|
+
|
|
319
|
+
#### T1.2: Another Task
|
|
320
|
+
- [x] **Status**: DONE
|
|
321
|
+
- **Complexity**: Medium
|
|
322
|
+
- **Dependencies**: T1.1
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Status values: `TODO`, `IN_PROGRESS`, `DONE`, `BLOCKED`
|
|
326
|
+
Complexity values: `Low`, `Medium`, `High`
|
|
327
|
+
|
|
328
|
+
### Table Format (Alternative)
|
|
329
|
+
|
|
330
|
+
```markdown
|
|
331
|
+
| ID | Task | Complexity | Status | Dependencies |
|
|
332
|
+
|-------|----------------|------------|--------|--------------|
|
|
333
|
+
| T1.1 | Setup Project | Low | TODO | - |
|
|
334
|
+
| T1.2 | Add Database | Medium | TODO | T1.1 |
|
|
335
|
+
| T1.3 | Create API | High | TODO | T1.1, T1.2 |
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Task ID Format
|
|
339
|
+
|
|
340
|
+
Valid task IDs:
|
|
341
|
+
- `T1.1`, `T1.2`, `T2.1` - Standard format
|
|
342
|
+
- `T5A.1`, `T5A.2`, `T5B.1` - Sub-phase format
|
|
343
|
+
- `T10.1`, `T10.15` - Multi-digit phases
|
|
344
|
+
|
|
345
|
+
Invalid task IDs:
|
|
346
|
+
- `Task1`, `T-1.1`, `T1-1` - Wrong format
|
|
@@ -694,60 +694,122 @@ try {
|
|
|
694
694
|
```
|
|
695
695
|
|
|
696
696
|
**Task generation from features:**
|
|
697
|
+
|
|
698
|
+
**CRITICAL: Use this EXACT markdown format for each task!**
|
|
699
|
+
|
|
700
|
+
```markdown
|
|
701
|
+
#### T{phase}.{num}: {Task Name}
|
|
702
|
+
- [ ] **Status**: TODO
|
|
703
|
+
- **Complexity**: Low/Medium/High
|
|
704
|
+
- **Dependencies**: None (or T1.1, T1.2)
|
|
705
|
+
- **Description**:
|
|
706
|
+
- Detail from specification
|
|
707
|
+
- Implementation notes
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
**Example generated tasks:**
|
|
711
|
+
|
|
712
|
+
```markdown
|
|
713
|
+
#### T2.1: Implement User Authentication
|
|
714
|
+
- [ ] **Status**: TODO
|
|
715
|
+
- **Complexity**: High
|
|
716
|
+
- **Dependencies**: T1.2
|
|
717
|
+
- **Description**:
|
|
718
|
+
- Setup JWT authentication
|
|
719
|
+
- Implement login/register endpoints
|
|
720
|
+
- Add password hashing
|
|
721
|
+
|
|
722
|
+
#### T2.2: Create User Dashboard
|
|
723
|
+
- [ ] **Status**: TODO
|
|
724
|
+
- **Complexity**: Medium
|
|
725
|
+
- **Dependencies**: T2.1
|
|
726
|
+
- **Description**:
|
|
727
|
+
- Build dashboard layout
|
|
728
|
+
- Display user statistics
|
|
729
|
+
- Add navigation menu
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
**Pseudo-code for task generation:**
|
|
697
733
|
```javascript
|
|
734
|
+
function generateTaskMarkdown(taskId, name, complexity, dependencies, description) {
|
|
735
|
+
const depStr = dependencies.length > 0 ? dependencies.join(", ") : "None"
|
|
736
|
+
const descLines = description.map(d => ` - ${d}`).join("\n")
|
|
737
|
+
|
|
738
|
+
return `#### ${taskId}: ${name}
|
|
739
|
+
- [ ] **Status**: TODO
|
|
740
|
+
- **Complexity**: ${complexity}
|
|
741
|
+
- **Dependencies**: ${depStr}
|
|
742
|
+
- **Description**:
|
|
743
|
+
${descLines}`
|
|
744
|
+
}
|
|
745
|
+
|
|
698
746
|
function generateTasks(features, phase) {
|
|
699
747
|
const tasks = []
|
|
700
748
|
let taskNum = 1
|
|
701
749
|
|
|
702
750
|
for (const feature of features) {
|
|
703
|
-
// Simple feature → 1 task
|
|
704
|
-
// Complex feature → 2-3 tasks
|
|
705
|
-
|
|
706
751
|
const complexity = estimateComplexity(feature)
|
|
707
752
|
|
|
708
753
|
if (complexity === "High") {
|
|
709
754
|
// Split into multiple tasks
|
|
710
|
-
tasks.push(
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
755
|
+
tasks.push(generateTaskMarkdown(
|
|
756
|
+
`T${phase}.${taskNum}`,
|
|
757
|
+
`Setup ${feature.name}`,
|
|
758
|
+
"Medium",
|
|
759
|
+
taskNum > 1 ? [`T${phase}.${taskNum-1}`] : [],
|
|
760
|
+
["Initialize component structure", "Setup dependencies"]
|
|
761
|
+
))
|
|
716
762
|
taskNum++
|
|
717
763
|
|
|
718
|
-
tasks.push(
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
764
|
+
tasks.push(generateTaskMarkdown(
|
|
765
|
+
`T${phase}.${taskNum}`,
|
|
766
|
+
`Implement ${feature.name} core logic`,
|
|
767
|
+
"High",
|
|
768
|
+
[`T${phase}.${taskNum-1}`],
|
|
769
|
+
["Implement business logic", "Add validation", "Handle edge cases"]
|
|
770
|
+
))
|
|
725
771
|
taskNum++
|
|
726
772
|
|
|
727
|
-
tasks.push(
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
773
|
+
tasks.push(generateTaskMarkdown(
|
|
774
|
+
`T${phase}.${taskNum}`,
|
|
775
|
+
`${feature.name} UI and integration`,
|
|
776
|
+
"Medium",
|
|
777
|
+
[`T${phase}.${taskNum-1}`],
|
|
778
|
+
["Build UI components", "Connect to backend", "Add error handling"]
|
|
779
|
+
))
|
|
734
780
|
taskNum++
|
|
735
781
|
} else {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
782
|
+
tasks.push(generateTaskMarkdown(
|
|
783
|
+
`T${phase}.${taskNum}`,
|
|
784
|
+
`Implement ${feature.name}`,
|
|
785
|
+
complexity,
|
|
786
|
+
[],
|
|
787
|
+
feature.description ? [feature.description] : ["Implement feature as specified"]
|
|
788
|
+
))
|
|
743
789
|
taskNum++
|
|
744
790
|
}
|
|
745
791
|
}
|
|
746
792
|
|
|
747
|
-
return tasks
|
|
793
|
+
return tasks.join("\n\n")
|
|
748
794
|
}
|
|
749
795
|
```
|
|
750
796
|
|
|
797
|
+
**IMPORTANT: Never use these WRONG formats:**
|
|
798
|
+
```markdown
|
|
799
|
+
❌ - T2.1: Task Name (bullet format - won't parse)
|
|
800
|
+
❌ 1. T2.1: Task Name (numbered format - won't parse)
|
|
801
|
+
❌ T2.1: Task Name (plain format - won't parse)
|
|
802
|
+
❌ ## T2.1: Task Name (wrong header level)
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
**Always use this CORRECT format:**
|
|
806
|
+
```markdown
|
|
807
|
+
✅ #### T2.1: Task Name
|
|
808
|
+
✅ - [ ] **Status**: TODO
|
|
809
|
+
✅ - **Complexity**: Medium
|
|
810
|
+
✅ - **Dependencies**: T2.0
|
|
811
|
+
```
|
|
812
|
+
|
|
751
813
|
**Write the file:**
|
|
752
814
|
```javascript
|
|
753
815
|
const outputPath = `./${outputFileName}`
|