sdd-pipeline 1.2.3 → 1.2.4
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/package.json +12 -9
- package/lib/converge-task.ps1 +0 -260
- package/lib/generate-tasks.ps1 +0 -450
- package/lib/output-dirs.ps1 +0 -461
- package/lib/sdd-check.ps1 +0 -130
- package/lib/shared-converge.ps1 +0 -270
- package/lib/verify-patterns.ps1 +0 -208
package/package.json
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sdd-pipeline",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"description": "Spec-Driven Development pipeline for Claude Code —
|
|
3
|
+
"version": "1.2.4",
|
|
4
|
+
"description": "Spec-Driven Development pipeline for Claude Code CLI — transforms raw feature requests into validated, shipped code through a self-correcting converge loop",
|
|
5
5
|
"bin": {
|
|
6
6
|
"sdd": "bin/sdd.js"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
|
-
"bin",
|
|
10
|
-
"lib",
|
|
11
|
-
"lib/
|
|
9
|
+
"bin/",
|
|
10
|
+
"lib/bmad.js",
|
|
11
|
+
"lib/config.js",
|
|
12
|
+
"lib/init.js",
|
|
13
|
+
"lib/sanitize.js",
|
|
14
|
+
"lib/bmad/",
|
|
15
|
+
"lib/bundle/"
|
|
12
16
|
],
|
|
13
17
|
"engines": {
|
|
14
18
|
"node": ">=18"
|
|
15
19
|
},
|
|
16
20
|
"preferGlobal": true,
|
|
17
|
-
"scripts": {
|
|
18
|
-
"build": "echo 'No build step needed — pure JS'"
|
|
19
|
-
},
|
|
20
21
|
"keywords": [
|
|
21
22
|
"sdd",
|
|
22
23
|
"spec-driven",
|
|
23
24
|
"claude-code",
|
|
24
|
-
"pipeline"
|
|
25
|
+
"pipeline",
|
|
26
|
+
"specification",
|
|
27
|
+
"development"
|
|
25
28
|
],
|
|
26
29
|
"license": "MIT"
|
|
27
30
|
}
|
package/lib/converge-task.ps1
DELETED
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
param(
|
|
2
|
-
[Parameter(Mandatory=$true)]
|
|
3
|
-
[string]$TaskId,
|
|
4
|
-
|
|
5
|
-
[string]$SpecFile = "",
|
|
6
|
-
|
|
7
|
-
[string]$TaskDir = "",
|
|
8
|
-
|
|
9
|
-
[string]$ConvergeDir = "",
|
|
10
|
-
|
|
11
|
-
[switch]$Strict
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
$ErrorActionPreference = "Continue"
|
|
15
|
-
$script:issuesFound = @()
|
|
16
|
-
|
|
17
|
-
# ============================================================
|
|
18
|
-
# SDD Path Resolution
|
|
19
|
-
# ============================================================
|
|
20
|
-
$SDD_OUTPUT_BASE = "sdd"
|
|
21
|
-
$SDD_SPEC_FILE = "sdd/SPEC.md"
|
|
22
|
-
$SDD_TASKS_DIR = "sdd/tasks"
|
|
23
|
-
$SDD_CONVERGE_DIR = "sdd/converge"
|
|
24
|
-
|
|
25
|
-
if (Test-Path ".sdd/config.json") {
|
|
26
|
-
try {
|
|
27
|
-
$config = Get-Content ".sdd/config.json" -Raw | ConvertFrom-Json
|
|
28
|
-
if ($config.output) {
|
|
29
|
-
if ($config.output.baseDir) { $SDD_OUTPUT_BASE = $config.output.baseDir }
|
|
30
|
-
if ($config.output.spec) { $SDD_SPEC_FILE = $config.output.spec }
|
|
31
|
-
if ($config.output.tasksDir) { $SDD_TASKS_DIR = $config.output.tasksDir }
|
|
32
|
-
if ($config.output.convergeDir) { $SDD_CONVERGE_DIR = $config.output.convergeDir }
|
|
33
|
-
}
|
|
34
|
-
} catch {}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
# Legacy fallback
|
|
38
|
-
if (-not $SpecFile) {
|
|
39
|
-
if (Test-Path "SPEC.md") { $SpecFile = "SPEC.md" }
|
|
40
|
-
elseif (Test-Path $SDD_SPEC_FILE) { $SpecFile = $SDD_SPEC_FILE }
|
|
41
|
-
else { $SpecFile = $SDD_SPEC_FILE }
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (-not $ConvergeDir) {
|
|
45
|
-
if (Test-Path "converge") { $ConvergeDir = "converge" }
|
|
46
|
-
else { $ConvergeDir = $SDD_CONVERGE_DIR }
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
# Ensure converge directory exists
|
|
50
|
-
if (-not (Test-Path $ConvergeDir)) {
|
|
51
|
-
New-Item -ItemType Directory -Path $ConvergeDir -Force | Out-Null
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
# Import shared functions
|
|
55
|
-
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
56
|
-
. "$scriptDir/shared-converge.ps1"
|
|
57
|
-
|
|
58
|
-
# Find Task File
|
|
59
|
-
function Get-TaskFile {
|
|
60
|
-
param([string]$TaskId, [string]$Dir)
|
|
61
|
-
|
|
62
|
-
if (-not $Dir) {
|
|
63
|
-
# Check new location first
|
|
64
|
-
if (Test-Path $SDD_TASKS_DIR) {
|
|
65
|
-
$dirs = Get-ChildItem -Path $SDD_TASKS_DIR -Filter "task-*-*" -Directory -ErrorAction SilentlyContinue
|
|
66
|
-
if ($dirs) {
|
|
67
|
-
$Dir = Join-Path $SDD_TASKS_DIR ($dirs | Select-Object -First 1).Name
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
# Fallback to legacy
|
|
71
|
-
if (-not $Dir) {
|
|
72
|
-
$dirs = Get-ChildItem -Filter "task-*-*" -Directory -ErrorAction SilentlyContinue
|
|
73
|
-
if ($dirs) { $Dir = ($dirs | Select-Object -First 1).Name }
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
if (-not $Dir) { return $null, $null }
|
|
77
|
-
|
|
78
|
-
$pattern = "$TaskId-*.md"
|
|
79
|
-
$files = Get-ChildItem -Path $Dir -Filter $pattern -ErrorAction SilentlyContinue
|
|
80
|
-
$files = $files | Where-Object { $_.Name -ne "MASTER-TASKS.md" }
|
|
81
|
-
return $Dir, ($files | Select-Object -First 1)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
# Generate Report
|
|
85
|
-
function New-ConvergeReport {
|
|
86
|
-
param(
|
|
87
|
-
[string]$TaskId,
|
|
88
|
-
[string[]]$Clauses,
|
|
89
|
-
[object[]]$Issues,
|
|
90
|
-
[int]$PassCount,
|
|
91
|
-
[int]$FailCount,
|
|
92
|
-
[string]$SpecFile,
|
|
93
|
-
[string]$OutputDir
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
$reportDir = Join-Path $OutputDir "task-$TaskId"
|
|
97
|
-
if (-not (Test-Path $reportDir)) {
|
|
98
|
-
New-Item -ItemType Directory -Path $reportDir -Force | Out-Null
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
$reportFile = Join-Path $reportDir "report.md"
|
|
102
|
-
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
103
|
-
|
|
104
|
-
$report = @"
|
|
105
|
-
# Converge Report: $TaskId
|
|
106
|
-
|
|
107
|
-
Generated: $timestamp by SDD Converge
|
|
108
|
-
|
|
109
|
-
## Summary
|
|
110
|
-
|
|
111
|
-
| Metric | Value |
|
|
112
|
-
|--------|-------|
|
|
113
|
-
| Clauses Found | $($Clauses.Count) |
|
|
114
|
-
| Clauses Passed | $PassCount |
|
|
115
|
-
| Clauses Failed | $FailCount |
|
|
116
|
-
| Status | $(if ($FailCount -eq 0) { 'PASS' } else { 'FAIL' }) |
|
|
117
|
-
|
|
118
|
-
## Clause Results
|
|
119
|
-
|
|
120
|
-
| Clause ID | Type | Status | Notes |
|
|
121
|
-
|-----------|------|--------|-------|
|
|
122
|
-
"@
|
|
123
|
-
|
|
124
|
-
foreach ($clauseId in $Clauses) {
|
|
125
|
-
$clauseType = Get-ClauseType -ClauseId $clauseId
|
|
126
|
-
$isFail = $clauseId -in $Issues.Clause
|
|
127
|
-
$status = if ($isFail) { "FAIL" } else { "PASS" }
|
|
128
|
-
$report += "`n| $clauseId | $clauseType | $status | [Text spec] |"
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
$report += @"
|
|
132
|
-
|
|
133
|
-
## Issues Found
|
|
134
|
-
|
|
135
|
-
| Clause | Issue | Location |
|
|
136
|
-
|--------|-------|----------|
|
|
137
|
-
"@
|
|
138
|
-
|
|
139
|
-
if ($Issues.Count -eq 0) {
|
|
140
|
-
$report += "`n| - | No issues found | - |"
|
|
141
|
-
} else {
|
|
142
|
-
foreach ($issue in $Issues) {
|
|
143
|
-
$report += "`n| $($issue.Clause) | $($issue.Issue) | $($issue.Location) |"
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
$report += @"
|
|
148
|
-
|
|
149
|
-
## Next Steps
|
|
150
|
-
|
|
151
|
-
$(if ($FailCount -eq 0) {
|
|
152
|
-
"- [ ] **PROCEED:** All checks pass -> Move to next task"
|
|
153
|
-
} else {
|
|
154
|
-
"- [ ] **FIX:** Address issues above -> Re-run converge
|
|
155
|
-
- [ ] **IF SPEC ISSUE:** Update SPEC.md clause -> Re-generate task"
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
Generated by SDD Per-Task Converge v1.1.0
|
|
160
|
-
"@
|
|
161
|
-
|
|
162
|
-
$report | Out-File -FilePath $reportFile -Encoding UTF8
|
|
163
|
-
return $reportFile
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
# Main Execution
|
|
167
|
-
Write-Host ""
|
|
168
|
-
Write-Host "========================================" -ForegroundColor Cyan
|
|
169
|
-
Write-Host " SDD Per-Task Converge: $TaskId" -ForegroundColor Cyan
|
|
170
|
-
Write-Host "========================================" -ForegroundColor Cyan
|
|
171
|
-
Write-Host ""
|
|
172
|
-
Write-Host "Output: $SDD_OUTPUT_BASE/" -ForegroundColor Gray
|
|
173
|
-
Write-Host ""
|
|
174
|
-
|
|
175
|
-
# Step 1: Find task file
|
|
176
|
-
$taskDir, $taskFile = Get-TaskFile -TaskId $TaskId -Dir $TaskDir
|
|
177
|
-
if (-not $taskFile) {
|
|
178
|
-
Write-Host "[FAIL] Task file for $TaskId not found" -ForegroundColor Red
|
|
179
|
-
exit 1
|
|
180
|
-
}
|
|
181
|
-
Write-Host "[PASS] Task file: $([System.IO.Path]::GetFileName($taskDir))/$($taskFile.Name)" -ForegroundColor Green
|
|
182
|
-
|
|
183
|
-
# Step 2: Find SPEC.md
|
|
184
|
-
if (-not (Test-Path $SpecFile)) {
|
|
185
|
-
Write-Host "[FAIL] SPEC file not found: $SpecFile" -ForegroundColor Red
|
|
186
|
-
exit 1
|
|
187
|
-
}
|
|
188
|
-
Write-Host "[PASS] SPEC file: $SpecFile" -ForegroundColor Green
|
|
189
|
-
|
|
190
|
-
# Step 3: Extract clauses from SPEC.md
|
|
191
|
-
$clauses = Get-SpecClauses -File $SpecFile
|
|
192
|
-
Write-Host "[INFO] Found $($clauses.Count) clause IDs in SPEC.md" -ForegroundColor Cyan
|
|
193
|
-
|
|
194
|
-
# Step 4: Get implementation files
|
|
195
|
-
$implFiles = Get-TaskFiles -TaskId $TaskId -TaskDir $taskDir
|
|
196
|
-
Write-Host "[INFO] Implementation files: $($implFiles.Count)" -ForegroundColor Cyan
|
|
197
|
-
foreach ($f in $implFiles) {
|
|
198
|
-
Write-Host " -> $f" -ForegroundColor Gray
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
# Step 5: Validate each clause
|
|
202
|
-
Write-Host ""
|
|
203
|
-
Write-Host "--- Clause Validation ---" -ForegroundColor Magenta
|
|
204
|
-
|
|
205
|
-
$passCount = 0
|
|
206
|
-
$failCount = 0
|
|
207
|
-
|
|
208
|
-
foreach ($clause in $clauses) {
|
|
209
|
-
$result = Test-ClauseMatch -ClauseId $clause.Id -ClauseText $clause.Text -ClauseType $clause.Type -Files $implFiles
|
|
210
|
-
|
|
211
|
-
if ($result.Found) {
|
|
212
|
-
$passCount++
|
|
213
|
-
Write-Host "[PASS] $($clause.Id)" -ForegroundColor Green
|
|
214
|
-
} else {
|
|
215
|
-
$failCount++
|
|
216
|
-
Write-Host "[FAIL] $($clause.Id)" -ForegroundColor Red
|
|
217
|
-
$script:issuesFound += @{
|
|
218
|
-
Clause = $clause.Id
|
|
219
|
-
Issue = "Not found in implementation"
|
|
220
|
-
Location = $result.Location
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
# Summary
|
|
226
|
-
Write-Host ""
|
|
227
|
-
Write-Host "========================================" -ForegroundColor Cyan
|
|
228
|
-
Write-Host " Summary" -ForegroundColor Cyan
|
|
229
|
-
Write-Host "========================================" -ForegroundColor Cyan
|
|
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
|
-
Write-Host ""
|
|
236
|
-
Write-Host " Issues Found:" -ForegroundColor Yellow
|
|
237
|
-
foreach ($issue in $script:issuesFound) {
|
|
238
|
-
Write-Host " - $($issue.Clause): $($issue.Issue)" -ForegroundColor Yellow
|
|
239
|
-
Write-Host " Location: $($issue.Location)" -ForegroundColor DarkGray
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
# Step 6: Generate report
|
|
244
|
-
$reportFile = New-ConvergeReport -TaskId $TaskId -Clauses $clauses.Id -Issues $script:issuesFound -PassCount $passCount -FailCount $failCount -SpecFile $SpecFile -OutputDir $ConvergeDir
|
|
245
|
-
Write-Host ""
|
|
246
|
-
Write-Host "[PASS] Report saved: $reportFile" -ForegroundColor Green
|
|
247
|
-
|
|
248
|
-
# Exit code
|
|
249
|
-
if ($failCount -gt 0) {
|
|
250
|
-
if ($Strict) {
|
|
251
|
-
Write-Host "[FAIL] Converge FAILED (strict mode)" -ForegroundColor Red
|
|
252
|
-
exit 1
|
|
253
|
-
} else {
|
|
254
|
-
Write-Host "[WARN] Converge completed with issues (non-strict)" -ForegroundColor Yellow
|
|
255
|
-
exit 0
|
|
256
|
-
}
|
|
257
|
-
} else {
|
|
258
|
-
Write-Host "[PASS] Converge PASSED" -ForegroundColor Green
|
|
259
|
-
exit 0
|
|
260
|
-
}
|