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.
@@ -61,7 +61,32 @@ If not authenticated, display error card:
61
61
  ╰──────────────────────────────────────────────────────────────────────────────╯
62
62
  ```
63
63
 
64
- ## Step 2: Fetch Projects (with Loading)
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 3: Display Projects Card
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: Show Creation Card
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 5: Link and Push
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 6: Show Success Card
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, show warning card:**
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
- │ ⚠️ WARNING
358
+ │ ⚠️ NO TASKS FOUND
201
359
  ├──────────────────────────────────────────────────────────────────────────────┤
202
360
  │ │
203
- No tasks were parsed from the plan.
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
- This could mean:
206
- • The plan format is not recognized
207
- • Tasks should use format: #### T1.1: Task Name
208
- Or table format: | T1.1 | Task Name | Low | TODO | - |
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
- │ • /planNext Verify your plan format
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 admin
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 admin
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 and admins can send invitations.
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 admin
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 admin
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 another admin or the project owner to change your role.
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: admin, editor, viewer
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
- id: `T${phase}.${taskNum}`,
712
- name: `Setup ${feature.name}`,
713
- complexity: "Medium",
714
- status: "TODO"
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
- id: `T${phase}.${taskNum}`,
720
- name: `Implement ${feature.name} core logic`,
721
- complexity: "High",
722
- status: "TODO",
723
- dependencies: [`T${phase}.${taskNum-1}`]
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
- id: `T${phase}.${taskNum}`,
729
- name: `${feature.name} UI and integration`,
730
- complexity: "Medium",
731
- status: "TODO",
732
- dependencies: [`T${phase}.${taskNum-1}`]
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
- // Single task
737
- tasks.push({
738
- id: `T${phase}.${taskNum}`,
739
- name: `Implement ${feature.name}`,
740
- complexity: complexity,
741
- status: "TODO"
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}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "planflow-plugin",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "PlanFlow CLI plugin for Claude Code - slash commands for project planning",
5
5
  "author": "PlanFlow <hello@planflow.tools>",
6
6
  "license": "MIT",