sdd-pipeline 1.2.4 → 1.2.7
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/bin/sdd.cjs +201 -0
- package/lib/bmad/index.js +20 -3
- package/lib/bundle/.claude/commands/sdd-check.md +153 -0
- package/lib/bundle/.claude/commands/sdd-cook.md +149 -167
- package/lib/bundle/.claude/commands/sdd-task-status.md +97 -27
- package/lib/bundle/bin/sdd.cjs +201 -0
- package/lib/bundle/bin/sdd.js +159 -0
- package/lib/bundle/commands/sdd-task-status.ps1 +82 -22
- package/lib/bundle/lib/bmad/confidence.js +129 -0
- package/lib/bundle/lib/bmad/index.js +157 -0
- package/lib/bundle/lib/bmad/problem-first.js +91 -0
- package/lib/bundle/lib/bmad/questions.js +110 -0
- package/lib/bundle/lib/bmad/synthesis.js +109 -0
- package/lib/bundle/lib/config.js +35 -0
- package/lib/bundle/lib/init.js +204 -0
- package/lib/bundle/lib/sanitize.js +10 -0
- package/lib/bundle/run-converge.ps1 +288 -42
- package/lib/bundle/skills/sdd-tasks/SKILL.md +259 -0
- package/lib/init.js +108 -32
- package/package.json +8 -8
- package/bin/sdd.js +0 -70
- package/lib/bmad.js +0 -54
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
param(
|
|
2
2
|
[string]$Url = "http://localhost:3000",
|
|
3
3
|
[switch]$Strict,
|
|
4
|
+
[switch]$SkipUrlCheck, # Skip URL/dev server checks (for static files)
|
|
4
5
|
[string]$ProjectDomain = "general",
|
|
5
6
|
[string]$TaskDir = "",
|
|
7
|
+
[string]$TaskId = "",
|
|
6
8
|
[string]$SpecFile = ""
|
|
7
9
|
)
|
|
8
10
|
|
|
11
|
+
# Import shared functions (inline - file may not exist)
|
|
12
|
+
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
13
|
+
$sharedPath = Join-Path $scriptDir "lib/shared-converge.ps1"
|
|
14
|
+
if (Test-Path $sharedPath) {
|
|
15
|
+
. $sharedPath
|
|
16
|
+
}
|
|
17
|
+
|
|
9
18
|
$ErrorActionPreference = "Continue"
|
|
10
19
|
$overallPass = $true
|
|
20
|
+
$script:issuesFound = @()
|
|
11
21
|
|
|
12
22
|
# ============================================================
|
|
13
23
|
# SDD Path Resolution
|
|
14
24
|
# ============================================================
|
|
25
|
+
# Check config for output directory
|
|
15
26
|
$SDD_OUTPUT_BASE = "sdd"
|
|
16
27
|
$SDD_CONVERGE_DIR = "sdd/converge"
|
|
17
28
|
$SDD_SPEC_FILE = "sdd/SPEC.md"
|
|
@@ -32,7 +43,7 @@ if (Test-Path ".sdd/config.json") {
|
|
|
32
43
|
# Legacy file fallback
|
|
33
44
|
if (-not $SpecFile) {
|
|
34
45
|
if (Test-Path "SPEC.md") { $SpecFile = "SPEC.md" }
|
|
35
|
-
elseif (Test-Path $SDD_SPEC_FILE) { $SpecFile = $SDD_SPEC_FILE }
|
|
46
|
+
elseif (Test-Path "$SDD_SPEC_FILE") { $SpecFile = $SDD_SPEC_FILE }
|
|
36
47
|
else { $SpecFile = $SDD_SPEC_FILE }
|
|
37
48
|
}
|
|
38
49
|
|
|
@@ -41,6 +52,7 @@ if (-not (Test-Path $SDD_CONVERGE_DIR)) {
|
|
|
41
52
|
New-Item -ItemType Directory -Path $SDD_CONVERGE_DIR -Force | Out-Null
|
|
42
53
|
}
|
|
43
54
|
|
|
55
|
+
# Helper Functions
|
|
44
56
|
function Test-UrlSafe {
|
|
45
57
|
param([string]$Url)
|
|
46
58
|
$parsed = [System.Uri]::new($Url)
|
|
@@ -71,7 +83,7 @@ function Wait-ForDevServer {
|
|
|
71
83
|
try {
|
|
72
84
|
$response = Invoke-WebRequest -Uri $Url -Method Get -TimeoutSec 5 -UseBasicParsing
|
|
73
85
|
if ($response.StatusCode -eq 200 -or $response.StatusCode -eq 301 -or $response.StatusCode -eq 302) {
|
|
74
|
-
Write-Host "[
|
|
86
|
+
Write-Host "[PASS] Dev server ready at $Url" -ForegroundColor Green
|
|
75
87
|
return $true
|
|
76
88
|
}
|
|
77
89
|
} catch {
|
|
@@ -79,49 +91,271 @@ function Wait-ForDevServer {
|
|
|
79
91
|
}
|
|
80
92
|
Start-Sleep -Seconds $RetryIntervalSeconds
|
|
81
93
|
}
|
|
82
|
-
Write-Host "[
|
|
94
|
+
Write-Host "[FAIL] Dev server failed to start within $TimeoutSeconds seconds" -ForegroundColor Red
|
|
83
95
|
return $false
|
|
84
96
|
}
|
|
85
97
|
|
|
86
98
|
function Update-SddConfig {
|
|
87
99
|
param([string]$Phase, [string]$Status)
|
|
88
100
|
if (Test-Path ".sdd/config.json") {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
101
|
+
try {
|
|
102
|
+
$config = Get-Content ".sdd/config.json" -Raw | ConvertFrom-Json
|
|
103
|
+
if ($config.phases -and $config.phases.($Phase)) {
|
|
104
|
+
$config.phases.($Phase).status = $Status
|
|
105
|
+
if ($Status -eq "completed" -and $config.phases.($Phase).PSObject.Properties.Name -contains "completedAt") {
|
|
106
|
+
$config.phases.($Phase).completedAt = (Get-Date -Format "yyyy-MM-dd")
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
$config | ConvertTo-Json -Depth 10 | Set-Content ".sdd/config.json"
|
|
110
|
+
} catch {
|
|
111
|
+
Write-Host "[WARN] Could not update .sdd/config.json: $_" -ForegroundColor Yellow
|
|
93
112
|
}
|
|
94
|
-
$config | ConvertTo-Json -Depth 10 | Set-Content ".sdd/config.json"
|
|
95
113
|
}
|
|
96
114
|
}
|
|
97
115
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
116
|
+
# Get-SpecClauses - Extract clause IDs from SPEC.md
|
|
117
|
+
function Get-SpecClauses {
|
|
118
|
+
param([string]$File)
|
|
119
|
+
$clauses = @()
|
|
120
|
+
if (Test-Path $File) {
|
|
121
|
+
$content = Get-Content $File -Raw
|
|
122
|
+
# Match [SC-xxx], [AC-xxx], [FE-xxx] patterns
|
|
123
|
+
$pattern = '\[([A-Z]{2,3}-\d{3,4})\]'
|
|
124
|
+
$matches = [regex]::Matches($content, $pattern)
|
|
125
|
+
foreach ($m in $matches) {
|
|
126
|
+
$id = $m.Groups[1].Value
|
|
127
|
+
if ($clauses -notcontains $id) {
|
|
128
|
+
$clauses += $id
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return $clauses
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# Test-ClauseMatch - Check if clause is in implementation
|
|
136
|
+
function Test-ClauseMatch {
|
|
137
|
+
param([string]$ClauseId, [string]$ClauseText, [string]$ClauseType, [string[]]$Files)
|
|
138
|
+
foreach ($file in $Files) {
|
|
139
|
+
if (Test-Path $file) {
|
|
140
|
+
$content = Get-Content $file -Raw
|
|
141
|
+
if ($content -match [regex]::Escape($ClauseText)) {
|
|
142
|
+
return @{ Found = $true; Location = $file }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return @{ Found = $false; Location = "Not found" }
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# Get-TaskFiles - Find files associated with a task
|
|
150
|
+
function Get-TaskFiles {
|
|
151
|
+
param([string]$TaskId, [string]$TaskDir)
|
|
152
|
+
$files = @()
|
|
153
|
+
$taskFile = Get-ChildItem -Path $TaskDir -Filter "${TaskId}-*.md" -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne "MASTER-TASKS.md" }
|
|
154
|
+
if ($taskFile) {
|
|
155
|
+
$content = Get-Content $taskFile.FullName -Raw
|
|
156
|
+
# Extract file names from "## Files to Modify" section
|
|
157
|
+
if ($content -match '(?s)## Files to (?:Modify|Create)\s*\n((?:- .+\n?)+)') {
|
|
158
|
+
$filesBlock = $matches[1]
|
|
159
|
+
$fileMatches = [regex]::Matches($filesBlock, '-\s+`([^`]+)`')
|
|
160
|
+
foreach ($fm in $fileMatches) {
|
|
161
|
+
$files += $fm.Groups[1].Value
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return $files
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
# Main Execution
|
|
169
|
+
Write-Host ""
|
|
170
|
+
Write-Host "========================================" -ForegroundColor Cyan
|
|
171
|
+
Write-Host " SDD Converge Validation" -ForegroundColor Cyan
|
|
172
|
+
Write-Host "========================================" -ForegroundColor Cyan
|
|
173
|
+
Write-Host ""
|
|
174
|
+
Write-Host " Domain: $ProjectDomain" -ForegroundColor Gray
|
|
175
|
+
if ($TaskId) {
|
|
176
|
+
Write-Host " Task: $TaskId" -ForegroundColor Gray
|
|
177
|
+
}
|
|
178
|
+
Write-Host ""
|
|
179
|
+
|
|
180
|
+
# Per-Task Mode
|
|
181
|
+
if ($TaskId) {
|
|
182
|
+
Write-Host "[INFO] Running per-task converge for $TaskId" -ForegroundColor Cyan
|
|
183
|
+
|
|
184
|
+
# Find task files
|
|
185
|
+
$implFiles = Get-TaskFiles -TaskId $TaskId -TaskDir $TaskDir
|
|
186
|
+
if ($implFiles.Count -eq 0) {
|
|
187
|
+
Write-Host "[WARN] Could not find implementation files for $TaskId" -ForegroundColor Yellow
|
|
188
|
+
} else {
|
|
189
|
+
Write-Host "[INFO] Implementation files: $($implFiles.Count)" -ForegroundColor Cyan
|
|
190
|
+
foreach ($f in $implFiles) {
|
|
191
|
+
Write-Host " -> $f" -ForegroundColor Gray
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
# Check SPEC
|
|
196
|
+
if (-not (Test-Path $SpecFile)) {
|
|
197
|
+
Write-Host "[FAIL] SPEC not found: $SpecFile" -ForegroundColor Red
|
|
198
|
+
$overallPass = $false
|
|
199
|
+
} else {
|
|
200
|
+
Write-Host "[PASS] SPEC file found: $SpecFile" -ForegroundColor Green
|
|
201
|
+
|
|
202
|
+
# Extract and verify clauses
|
|
203
|
+
$clauses = Get-SpecClauses -File $SpecFile
|
|
204
|
+
Write-Host "[INFO] Found $($clauses.Count) clause IDs in SPEC" -ForegroundColor Cyan
|
|
205
|
+
|
|
206
|
+
if ($clauses.Count -gt 0) {
|
|
207
|
+
Write-Host ""
|
|
208
|
+
Write-Host "--- Clause Validation ---" -ForegroundColor Magenta
|
|
209
|
+
|
|
210
|
+
$passCount = 0
|
|
211
|
+
$failCount = 0
|
|
212
|
+
|
|
213
|
+
foreach ($clause in $clauses) {
|
|
214
|
+
$result = Test-ClauseMatch -ClauseId $clause.Id -ClauseText $clause.Text -ClauseType $clause.Type -Files $implFiles
|
|
215
|
+
|
|
216
|
+
if ($result.Found) {
|
|
217
|
+
$passCount++
|
|
218
|
+
Write-Host "[PASS] $($clause.Id)" -ForegroundColor Green
|
|
219
|
+
} else {
|
|
220
|
+
$failCount++
|
|
221
|
+
Write-Host "[FAIL] $($clause.Id)" -ForegroundColor Red
|
|
222
|
+
$script:issuesFound += @{
|
|
223
|
+
Clause = $clause.Id
|
|
224
|
+
Issue = "Not found in implementation"
|
|
225
|
+
Location = $result.Location
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
Write-Host ""
|
|
231
|
+
Write-Host " Clauses Passed: $passCount" -ForegroundColor Green
|
|
232
|
+
Write-Host " Clauses Failed: $failCount" -ForegroundColor $(if ($failCount -gt 0) { "Red" } else { "Green" })
|
|
233
|
+
|
|
234
|
+
if ($failCount -gt 0) {
|
|
235
|
+
$overallPass = $false
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
# Generate task converge report in sdd/converge/
|
|
241
|
+
$reportDir = "$SDD_CONVERGE_DIR/task-$TaskId"
|
|
242
|
+
if (-not (Test-Path $reportDir)) {
|
|
243
|
+
New-Item -ItemType Directory -Path $reportDir -Force | Out-Null
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
247
|
+
$passCount = $clauses.Count - $script:issuesFound.Count
|
|
248
|
+
|
|
249
|
+
$report = @"
|
|
250
|
+
# Converge Report: $TaskId
|
|
251
|
+
|
|
252
|
+
Generated: $timestamp by SDD Converge
|
|
253
|
+
|
|
254
|
+
## Summary
|
|
255
|
+
|
|
256
|
+
| Metric | Value |
|
|
257
|
+
|--------|-------|
|
|
258
|
+
| Clauses Found | $($clauses.Count) |
|
|
259
|
+
| Clauses Passed | $passCount |
|
|
260
|
+
| Clauses Failed | $($script:issuesFound.Count) |
|
|
261
|
+
| Status | $(if ($script:issuesFound.Count -eq 0) { 'PASS' } else { 'FAIL' }) |
|
|
262
|
+
|
|
263
|
+
## Clause Results
|
|
264
|
+
|
|
265
|
+
| Clause ID | Type | Status | Location |
|
|
266
|
+
|-----------|------|--------|----------|
|
|
267
|
+
"@
|
|
268
|
+
|
|
269
|
+
foreach ($clause in $clauses) {
|
|
270
|
+
$isFail = $clause.Id -in $script:issuesFound.Clause
|
|
271
|
+
$status = if ($isFail) { "FAIL" } else { "PASS" }
|
|
272
|
+
$location = if ($isFail) {
|
|
273
|
+
($script:issuesFound | Where-Object { $_.Clause -eq $clause.Id }).Location
|
|
274
|
+
} else {
|
|
275
|
+
"Verified"
|
|
276
|
+
}
|
|
277
|
+
$report += "`n| $($clause.Id) | $($clause.Type) | $status | $location |"
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
$report += @"
|
|
281
|
+
|
|
282
|
+
## Issues Found
|
|
283
|
+
|
|
284
|
+
| Clause | Issue | Location |
|
|
285
|
+
|--------|-------|----------|
|
|
286
|
+
"@
|
|
287
|
+
|
|
288
|
+
if ($script:issuesFound.Count -eq 0) {
|
|
289
|
+
$report += "`n| - | No issues found | - |"
|
|
290
|
+
} else {
|
|
291
|
+
foreach ($issue in $script:issuesFound) {
|
|
292
|
+
$report += "`n| $($issue.Clause) | $($issue.Issue) | $($issue.Location) |"
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
$report += @"
|
|
297
|
+
|
|
298
|
+
## Next Steps
|
|
299
|
+
|
|
300
|
+
$(if ($script:issuesFound.Count -eq 0) {
|
|
301
|
+
"- [ ] **PROCEED:** All checks pass -> Move to next task"
|
|
302
|
+
} else {
|
|
303
|
+
"- [ ] **FIX:** Address issues above -> Re-run converge
|
|
304
|
+
- [ ] **IF SPEC ISSUE:** Update SPEC.md clause -> Re-generate task"
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
Generated by SDD Per-Task Converge
|
|
309
|
+
"@
|
|
310
|
+
|
|
311
|
+
$reportFile = Join-Path $reportDir "report.md"
|
|
312
|
+
$report | Out-File -FilePath $reportFile -Encoding UTF8
|
|
313
|
+
Write-Host ""
|
|
314
|
+
Write-Host "[INFO] Report saved: $reportFile" -ForegroundColor Cyan
|
|
315
|
+
|
|
316
|
+
# Final decision
|
|
317
|
+
Write-Host ""
|
|
318
|
+
if ($overallPass) {
|
|
319
|
+
Write-Host "[PASS] CONVERGE PASSED" -ForegroundColor Green
|
|
320
|
+
Update-SddConfig -Phase "phase5" -Status "completed"
|
|
321
|
+
} else {
|
|
322
|
+
Write-Host "[FAIL] CONVERGE FAILED" -ForegroundColor Red
|
|
323
|
+
if ($Strict) {
|
|
324
|
+
Update-SddConfig -Phase "phase5" -Status "failed"
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
exit $(if ($overallPass -or -not $Strict) { 0 } else { 1 })
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
# Full Project Mode
|
|
332
|
+
Write-Host "[INFO] Running full project converge" -ForegroundColor Cyan
|
|
101
333
|
Write-Host ""
|
|
102
334
|
|
|
103
335
|
# Check SPEC file
|
|
104
336
|
if (Test-Path $SpecFile) {
|
|
105
|
-
Write-Host "[
|
|
337
|
+
Write-Host "[PASS] SPEC file found: $SpecFile" -ForegroundColor Green
|
|
106
338
|
} else {
|
|
107
|
-
Write-Host "[
|
|
339
|
+
Write-Host "[FAIL] SPEC file MISSING: $SpecFile" -ForegroundColor Red
|
|
108
340
|
$overallPass = $false
|
|
109
341
|
}
|
|
110
342
|
|
|
111
343
|
# Find task directory (check new path first, then legacy)
|
|
112
344
|
if (-not $TaskDir) {
|
|
345
|
+
# Check new location
|
|
113
346
|
if (Test-Path $SDD_TASKS_DIR) {
|
|
114
347
|
$taskDirs = Get-ChildItem -Path $SDD_TASKS_DIR -Filter "task-*-*" -Directory -ErrorAction SilentlyContinue
|
|
115
348
|
if ($taskDirs) {
|
|
116
349
|
$TaskDir = Join-Path $SDD_TASKS_DIR ($taskDirs | Select-Object -First 1).Name
|
|
117
|
-
Write-Host "[
|
|
350
|
+
Write-Host "[PASS] Task directory found: $TaskDir" -ForegroundColor Green
|
|
118
351
|
}
|
|
119
352
|
}
|
|
353
|
+
# Fallback to legacy location
|
|
120
354
|
if (-not $TaskDir) {
|
|
121
355
|
$legacyTaskDirs = Get-ChildItem -Filter "task-*-*" -Directory -ErrorAction SilentlyContinue
|
|
122
356
|
if ($legacyTaskDirs) {
|
|
123
|
-
$TaskDir = ($legacyTaskDirs | Select-Object -First 1).
|
|
124
|
-
Write-Host "[
|
|
357
|
+
$TaskDir = ($legacyTaskDirs | Select-Object -First 1).Name
|
|
358
|
+
Write-Host "[PASS] Task directory found: $TaskDir (legacy location)" -ForegroundColor Green
|
|
125
359
|
}
|
|
126
360
|
}
|
|
127
361
|
}
|
|
@@ -129,71 +363,83 @@ if (-not $TaskDir) {
|
|
|
129
363
|
if ($TaskDir) {
|
|
130
364
|
$masterTasks = Join-Path $TaskDir "MASTER-TASKS.md"
|
|
131
365
|
if (Test-Path $masterTasks) {
|
|
132
|
-
Write-Host "[
|
|
366
|
+
Write-Host "[PASS] $masterTasks exists" -ForegroundColor Green
|
|
133
367
|
} else {
|
|
134
|
-
Write-Host "[
|
|
368
|
+
Write-Host "[FAIL] $masterTasks MISSING" -ForegroundColor Red
|
|
135
369
|
$overallPass = $false
|
|
136
370
|
}
|
|
137
371
|
|
|
138
372
|
Write-Host ""
|
|
139
|
-
Write-Host "--- Task Validation ---" -ForegroundColor
|
|
373
|
+
Write-Host "--- Task Validation ---" -ForegroundColor Magenta
|
|
140
374
|
$taskFiles = Get-ChildItem -Path $TaskDir -Filter "T-*.md" -ErrorAction SilentlyContinue
|
|
141
375
|
$taskFiles = $taskFiles | Where-Object { $_.Name -ne "MASTER-TASKS.md" }
|
|
142
|
-
Write-Host "Found $($taskFiles.Count) task files" -ForegroundColor Cyan
|
|
376
|
+
Write-Host "[INFO] Found $($taskFiles.Count) task files" -ForegroundColor Cyan
|
|
143
377
|
foreach ($task in $taskFiles) {
|
|
144
|
-
Write-Host "[
|
|
378
|
+
Write-Host "[PASS] $($task.Name)" -ForegroundColor Green
|
|
145
379
|
}
|
|
146
380
|
} else {
|
|
147
|
-
Write-Host "[
|
|
148
|
-
$overallPass = $false
|
|
381
|
+
Write-Host "[WARN] No task directory found" -ForegroundColor Yellow
|
|
149
382
|
}
|
|
150
383
|
|
|
151
384
|
if (-not $overallPass) {
|
|
152
385
|
Write-Host ""
|
|
153
|
-
Write-Host "Converge FAILED: Missing artifacts" -ForegroundColor Red
|
|
386
|
+
Write-Host "[FAIL] Converge FAILED: Missing artifacts" -ForegroundColor Red
|
|
154
387
|
exit 1
|
|
155
388
|
}
|
|
156
389
|
|
|
157
390
|
Write-Host ""
|
|
158
|
-
Write-Host "--- URL Validation ---" -ForegroundColor
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
391
|
+
Write-Host "--- URL Validation ---" -ForegroundColor Magenta
|
|
392
|
+
if ($SkipUrlCheck) {
|
|
393
|
+
Write-Host "[SKIP] URL check skipped (use for static files)" -ForegroundColor Yellow
|
|
394
|
+
} else {
|
|
395
|
+
try {
|
|
396
|
+
Test-UrlSafe -Url $Url
|
|
397
|
+
Write-Host "[PASS] URL is safe: $Url" -ForegroundColor Green
|
|
398
|
+
} catch {
|
|
399
|
+
Write-Host "[FAIL] URL validation failed: $_" -ForegroundColor Red
|
|
400
|
+
$overallPass = $false
|
|
401
|
+
}
|
|
166
402
|
|
|
167
|
-
Write-Host ""
|
|
168
|
-
Write-Host "--- Dev Server Health Check ---" -ForegroundColor
|
|
169
|
-
$serverReady = Wait-ForDevServer -Url $Url -TimeoutSeconds 30
|
|
170
|
-
if (-not $serverReady) {
|
|
171
|
-
|
|
403
|
+
Write-Host ""
|
|
404
|
+
Write-Host "--- Dev Server Health Check ---" -ForegroundColor Magenta
|
|
405
|
+
$serverReady = Wait-ForDevServer -Url $Url -TimeoutSeconds 30
|
|
406
|
+
if (-not $serverReady) {
|
|
407
|
+
Write-Host "[WARN] Dev server not available -- skipping live checks" -ForegroundColor Yellow
|
|
408
|
+
}
|
|
172
409
|
}
|
|
173
410
|
|
|
174
411
|
Write-Host ""
|
|
175
|
-
Write-Host "--- SPEC.md Validation ---" -ForegroundColor
|
|
412
|
+
Write-Host "--- SPEC.md Validation ---" -ForegroundColor Magenta
|
|
176
413
|
if (Test-Path $SpecFile) {
|
|
177
414
|
$specContent = Get-Content $SpecFile -Raw
|
|
178
415
|
$requiredSections = @("Overview", "User Stories", "Functional Requirements", "Success Criteria")
|
|
179
416
|
foreach ($section in $requiredSections) {
|
|
180
417
|
if ($specContent -match $section) {
|
|
181
|
-
Write-Host "[
|
|
418
|
+
Write-Host "[PASS] SPEC.md has '$section' section" -ForegroundColor Green
|
|
182
419
|
} else {
|
|
183
|
-
Write-Host "[
|
|
420
|
+
Write-Host "[FAIL] SPEC.md missing '$section' section" -ForegroundColor Red
|
|
184
421
|
$overallPass = $false
|
|
185
422
|
}
|
|
186
423
|
}
|
|
424
|
+
|
|
425
|
+
# Check for clause IDs
|
|
426
|
+
$clauses = Get-SpecClauses -File $SpecFile
|
|
427
|
+
if ($clauses.Count -gt 0) {
|
|
428
|
+
Write-Host ""
|
|
429
|
+
Write-Host "[INFO] SPEC.md contains $($clauses.Count) clause IDs" -ForegroundColor Cyan
|
|
430
|
+
Write-Host " Run per-task converge for detailed validation" -ForegroundColor Gray
|
|
431
|
+
}
|
|
187
432
|
}
|
|
188
433
|
|
|
189
434
|
Write-Host ""
|
|
435
|
+
Write-Host "========================================" -ForegroundColor Cyan
|
|
190
436
|
if ($overallPass) {
|
|
191
|
-
Write-Host "
|
|
437
|
+
Write-Host "[PASS] CONVERGE PASSED" -ForegroundColor Green
|
|
192
438
|
Update-SddConfig -Phase "phase5" -Status "completed"
|
|
193
439
|
Update-SddConfig -Phase "phase4" -Status "completed"
|
|
194
440
|
exit 0
|
|
195
441
|
} else {
|
|
196
|
-
Write-Host "
|
|
442
|
+
Write-Host "[FAIL] CONVERGE FAILED" -ForegroundColor Red
|
|
197
443
|
if ($Strict) {
|
|
198
444
|
Update-SddConfig -Phase "phase5" -Status "failed"
|
|
199
445
|
exit 1
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sdd-tasks
|
|
3
|
+
description: "SDD Phase 3 task generation. Read SPEC.md, extract features and testing requirements, generate modular tasks (≤2 hours each) in sdd/tasks/."
|
|
4
|
+
user-invocable: true
|
|
5
|
+
when_to_use: "After /sdd-spec generates SPEC.md. Run /sdd-tasks to break SPEC into tasks."
|
|
6
|
+
category: sdd
|
|
7
|
+
keywords: [sdd, tasks, task-generation, phase3]
|
|
8
|
+
argument-hint: "[--spec SPEC.md] [--output sdd/tasks/]"
|
|
9
|
+
metadata:
|
|
10
|
+
author: xdm-kit
|
|
11
|
+
version: "1.0.0"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# SDD Tasks — Phase 3 Task Generation
|
|
15
|
+
|
|
16
|
+
Generate modular, independently verifiable tasks from SPEC.md.
|
|
17
|
+
|
|
18
|
+
**Reads:** `sdd/SPEC.md`
|
|
19
|
+
**Outputs:** `sdd/tasks/task-{timestamp}-{project}/MASTER-TASKS.md` + `T-XXX-*.md`
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Process Flow
|
|
24
|
+
|
|
25
|
+
```mermaid
|
|
26
|
+
flowchart TD
|
|
27
|
+
A[Read SPEC.md] --> B{SPEC valid?}
|
|
28
|
+
B -->|No| E[ERROR: SPEC not found]
|
|
29
|
+
B -->|Yes| C[Extract Features]
|
|
30
|
+
C --> D[Extract Testing Requirements]
|
|
31
|
+
D --> F[Generate Tasks]
|
|
32
|
+
F --> G[Create Task Directory]
|
|
33
|
+
G --> H[Write MASTER-TASKS.md]
|
|
34
|
+
H --> I[Write T-XXX-*.md files]
|
|
35
|
+
I --> J[Summary]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Step 1: Prerequisites Check
|
|
41
|
+
|
|
42
|
+
1. **SPEC.md exists** at `sdd/SPEC.md`
|
|
43
|
+
2. **SPEC.md has required sections:**
|
|
44
|
+
- Section 4.1 (Core Features)
|
|
45
|
+
- Section 9 (Testing Requirements) - if present
|
|
46
|
+
|
|
47
|
+
If SPEC not found:
|
|
48
|
+
```
|
|
49
|
+
ERROR: SPEC.md not found.
|
|
50
|
+
Run /sdd-spec first.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Step 2: Extract Information
|
|
56
|
+
|
|
57
|
+
### From SPEC.md Section 4.1 (Core Features)
|
|
58
|
+
|
|
59
|
+
Parse each feature block:
|
|
60
|
+
```
|
|
61
|
+
#### [Feature Name]
|
|
62
|
+
|
|
63
|
+
- **Description:** [What it does]
|
|
64
|
+
- **States:** [List states]
|
|
65
|
+
|
|
66
|
+
**Acceptance criteria:**
|
|
67
|
+
- [AC-XXX] [Criterion]
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Extract:
|
|
71
|
+
- Feature name
|
|
72
|
+
- Implementation steps
|
|
73
|
+
- Acceptance criteria
|
|
74
|
+
|
|
75
|
+
### From SPEC.md Section 9 (Testing Requirements)
|
|
76
|
+
|
|
77
|
+
Parse test categories and specifications:
|
|
78
|
+
```
|
|
79
|
+
### 9.1 Test Categories
|
|
80
|
+
| Category | Priority |
|
|
81
|
+
|----------|----------|
|
|
82
|
+
| Unit Tests | MUST |
|
|
83
|
+
| Integration Tests | MUST |
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Extract:
|
|
87
|
+
- Test categories (Unit, Integration, E2E, Accessibility)
|
|
88
|
+
- Test specifications from 9.2-9.4
|
|
89
|
+
- Test data from 9.5
|
|
90
|
+
|
|
91
|
+
### From SPEC.md Section 2 (User Stories)
|
|
92
|
+
|
|
93
|
+
Parse user stories:
|
|
94
|
+
```
|
|
95
|
+
- **As a** [user], **I want** [action], **so that** [benefit]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Extract:
|
|
99
|
+
- User stories for context
|
|
100
|
+
- Priority (Must Have vs Nice to Have)
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Step 3: Generate Tasks
|
|
105
|
+
|
|
106
|
+
### Task Structure
|
|
107
|
+
|
|
108
|
+
Each task:
|
|
109
|
+
- Takes ≤2 hours
|
|
110
|
+
- Independently verifiable
|
|
111
|
+
- Has frontmatter with dependencies
|
|
112
|
+
|
|
113
|
+
### Task Categories
|
|
114
|
+
|
|
115
|
+
| Phase | Category | Description |
|
|
116
|
+
|-------|----------|-------------|
|
|
117
|
+
| 1 | Setup | Project initialization, configs |
|
|
118
|
+
| 2-4 | Feature | Core feature implementation |
|
|
119
|
+
| N-3 | Test | Unit, Integration, E2E, Accessibility |
|
|
120
|
+
| N-2 | Polish | Final styling, edge cases |
|
|
121
|
+
| N-1 | Converge | Validation and testing |
|
|
122
|
+
| N | Deploy | Deployment preparation |
|
|
123
|
+
|
|
124
|
+
### Task File Template
|
|
125
|
+
|
|
126
|
+
```markdown
|
|
127
|
+
---
|
|
128
|
+
name: T-XXX-task-name
|
|
129
|
+
description: "[Brief description]"
|
|
130
|
+
phase: N
|
|
131
|
+
estimate: 1h
|
|
132
|
+
spec_sections: ["4.1", "9.1"]
|
|
133
|
+
depends_on: ["T-XXX"]
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
# T-XXX: Task Name
|
|
137
|
+
|
|
138
|
+
## Files to Modify/Create
|
|
139
|
+
- [file1]
|
|
140
|
+
- [file2]
|
|
141
|
+
|
|
142
|
+
## Implementation Steps
|
|
143
|
+
|
|
144
|
+
1. [Step 1]
|
|
145
|
+
2. [Step 2]
|
|
146
|
+
3. [Step 3]
|
|
147
|
+
|
|
148
|
+
## Verification
|
|
149
|
+
|
|
150
|
+
- [ ] [Check 1]
|
|
151
|
+
- [ ] [Check 2]
|
|
152
|
+
- [ ] [Check 3]
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Step 4: Generate MASTER-TASKS.md
|
|
158
|
+
|
|
159
|
+
```markdown
|
|
160
|
+
# MASTER-TASKS — {Project Name}
|
|
161
|
+
|
|
162
|
+
## Task Index
|
|
163
|
+
|
|
164
|
+
| ID | Name | Estimate | Status |
|
|
165
|
+
|----|------|----------|--------|
|
|
166
|
+
| T-001 | Setup | 1h | [ ] |
|
|
167
|
+
| T-002 | Feature A | 1h | [ ] |
|
|
168
|
+
| ... | ... | ... | ... |
|
|
169
|
+
| T-NNN | Final | 1h | [ ] |
|
|
170
|
+
|
|
171
|
+
## Progress
|
|
172
|
+
|
|
173
|
+
- Completed: 0 / NNN
|
|
174
|
+
- In Progress: 0
|
|
175
|
+
- Pending: NNN
|
|
176
|
+
|
|
177
|
+
## Dependencies
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
T-001
|
|
181
|
+
T-002 ──┬── T-004
|
|
182
|
+
T-003 ──┴── T-005 ── T-006
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Notes
|
|
186
|
+
|
|
187
|
+
Generated from: SPEC.md
|
|
188
|
+
Test categories: {from Section 9.1}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Step 5: Output Summary
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
=== SDD Tasks Generated ===
|
|
197
|
+
|
|
198
|
+
Project: {name}
|
|
199
|
+
Tasks: NNN
|
|
200
|
+
Test categories: {list}
|
|
201
|
+
|
|
202
|
+
Task directory: sdd/tasks/task-{timestamp}-{project}/
|
|
203
|
+
|
|
204
|
+
Tasks:
|
|
205
|
+
T-001: Setup (1h)
|
|
206
|
+
T-002: Feature A (1h)
|
|
207
|
+
T-003: Feature B (1h)
|
|
208
|
+
T-004: Unit Tests (1h)
|
|
209
|
+
T-005: Integration Tests (1h)
|
|
210
|
+
T-006: Polish (1h)
|
|
211
|
+
T-007: Converge (1h)
|
|
212
|
+
|
|
213
|
+
Next: /sdd-cook --all
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Error Handling
|
|
219
|
+
|
|
220
|
+
| Error | Message | Action |
|
|
221
|
+
|-------|---------|--------|
|
|
222
|
+
| SPEC.md not found | ERROR: SPEC.md not found | Exit 1 |
|
|
223
|
+
| Empty features | WARN: No features found | Generate setup only |
|
|
224
|
+
| Missing test section | INFO: No testing section | Skip test tasks |
|
|
225
|
+
| Directory exists | WARN: Overwriting existing | Confirm or skip |
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Testing Requirements Integration
|
|
230
|
+
|
|
231
|
+
Section 9 of SPEC.md defines testing requirements. Generate test tasks:
|
|
232
|
+
|
|
233
|
+
### Unit Tests Task
|
|
234
|
+
- Parse Section 9.2 for test specifications
|
|
235
|
+
- Create test file templates
|
|
236
|
+
- Include coverage targets
|
|
237
|
+
|
|
238
|
+
### Integration Tests Task
|
|
239
|
+
- Parse Section 9.3 for flow specifications
|
|
240
|
+
- Map user flows to test scenarios
|
|
241
|
+
- Create Given/When/Then templates
|
|
242
|
+
|
|
243
|
+
### E2E Tests Task
|
|
244
|
+
- Parse Section 9.4 for scenario specifications
|
|
245
|
+
- Create complete user journey tests
|
|
246
|
+
- Include browser automation
|
|
247
|
+
|
|
248
|
+
### Accessibility Tests Task
|
|
249
|
+
- Parse accessibility requirements
|
|
250
|
+
- Include WCAG compliance checks
|
|
251
|
+
- Create axe-core/Lighthouse tests
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## References
|
|
256
|
+
|
|
257
|
+
- `references/task-template.md` - Task file template
|
|
258
|
+
- `references/test-task-template.md` - Test task template
|
|
259
|
+
- `references/task-master-template.md` - MASTER-TASKS template
|