sdd-pipeline 1.2.2 → 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/lib/sdd-check.ps1 DELETED
@@ -1,130 +0,0 @@
1
- param(
2
- [Parameter(Mandatory=$true, Position=0)]
3
- [string]$FilePath,
4
-
5
- [string]$Section = "",
6
-
7
- [string]$SpecFile = "SPEC.md",
8
-
9
- [ValidateSet("table", "json", "minimal")]
10
- [string]$OutputFormat = "table"
11
- )
12
-
13
- # Import shared functions
14
- $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
15
- . "$scriptDir/shared-converge.ps1"
16
-
17
- $ErrorActionPreference = "Continue"
18
-
19
- # Resolve Files
20
- $files = @()
21
- if ($FilePath -match '\*|\?') {
22
- $files = Get-ChildItem -Path $FilePath -File -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName }
23
- } else {
24
- if (Test-Path $FilePath) {
25
- $files = @((Resolve-Path $FilePath).Path)
26
- }
27
- }
28
-
29
- if ($files.Count -eq 0) {
30
- Write-Error "No files found matching: $FilePath"
31
- exit 1
32
- }
33
-
34
- # Load SPEC
35
- if (-not (Test-Path $SpecFile)) {
36
- Write-Error "SPEC file not found: $SpecFile"
37
- exit 1
38
- }
39
-
40
- Write-Host ""
41
- Write-Host "========================================" -ForegroundColor Cyan
42
- Write-Host " SDD Check" -ForegroundColor Cyan
43
- Write-Host "========================================" -ForegroundColor Cyan
44
- Write-Host ""
45
- Write-Host " Files: $($files.Count)" -ForegroundColor Gray
46
- Write-Host " Spec: $SpecFile" -ForegroundColor Gray
47
- Write-Host ""
48
-
49
- # Get clauses from SPEC
50
- $clauses = Get-SpecClauses -File $SpecFile
51
- Write-Host " Clauses found: $($clauses.Count)" -ForegroundColor Gray
52
- Write-Host ""
53
-
54
- if ($clauses.Count -eq 0) {
55
- Write-Host "[WARN] No clause IDs found in SPEC.md" -ForegroundColor Yellow
56
- Write-Host " Add clause IDs like [SC-001], [SC-COLOR-001] to SPEC.md" -ForegroundColor Yellow
57
- exit 0
58
- }
59
-
60
- # Filter by section if specified
61
- if ($Section) {
62
- $specContent = Get-Content $SpecFile -Raw
63
- if ($specContent -match "(?s)##\s+$Section.*?(?=\n##\s+|\Z)") {
64
- $sectionText = $Matches[0]
65
- $filtered = @()
66
- foreach ($clause in $clauses) {
67
- if ($sectionText -match "\[$($clause.Id)\]") {
68
- $filtered += $clause
69
- }
70
- }
71
- $clauses = $filtered
72
- Write-Host " Section: $Section -> $($clauses.Count) clauses" -ForegroundColor Gray
73
- }
74
- }
75
-
76
- # Check each clause
77
- $results = @()
78
- $passCount = 0
79
- $failCount = 0
80
-
81
- foreach ($clause in $clauses) {
82
- $result = Test-ClauseMatch -ClauseId $clause.Id -ClauseText $clause.Text -ClauseType $clause.Type -Files $files
83
- $results += $result
84
-
85
- if ($result.Found) {
86
- $passCount++
87
- } else {
88
- $failCount++
89
- }
90
- }
91
-
92
- # Output
93
- if ($OutputFormat -eq "json") {
94
- $results | ConvertTo-Json -Depth 10
95
- } elseif ($OutputFormat -eq "minimal") {
96
- foreach ($r in $results) {
97
- $status = if ($r.Found) { "[PASS]" } else { "[FAIL]" }
98
- Write-Host "$status $($r.ClauseId)"
99
- }
100
- } else {
101
- # Table format
102
- $maxIdLen = [Math]::Max(10, ($results | ForEach-Object { $_.ClauseId.Length } | Measure-Object -Maximum).Maximum)
103
- $maxTypeLen = [Math]::Max(10, ($results | ForEach-Object { $_.Type.Length } | Measure-Object -Maximum).Maximum)
104
-
105
- foreach ($r in $results) {
106
- $status = if ($r.Found) { "[PASS]" } else { "[FAIL]" }
107
- $color = if ($r.Found) { "Green" } else { "Red" }
108
- Write-Host "$status $($r.ClauseId)" -ForegroundColor $color
109
- Write-Host " Type: $($r.Type) | Location: $($r.Location)" -ForegroundColor Gray
110
- }
111
- }
112
-
113
- # Summary
114
- Write-Host ""
115
- Write-Host "========================================" -ForegroundColor Cyan
116
- Write-Host " Result: $passCount passed, $failCount failed" -ForegroundColor $(if ($failCount -eq 0) { "Green" } else { "Yellow" })
117
- Write-Host "========================================" -ForegroundColor Cyan
118
- Write-Host ""
119
-
120
- if ($failCount -gt 0) {
121
- Write-Host "Missing clauses:" -ForegroundColor Yellow
122
- $results | Where-Object { -not $_.Found } | ForEach-Object {
123
- $shortText = if ($_.Text) { $_.Text.Substring(0, [Math]::Min(50, $_.Text.Length)) } else { "(no text)" }
124
- Write-Host " [FAIL] $($_.ClauseId): $shortText" -ForegroundColor Red
125
- }
126
- Write-Host ""
127
- }
128
-
129
- # Exit code
130
- exit $(if ($failCount -eq 0) { 0 } else { 1 })
@@ -1,270 +0,0 @@
1
- # SDD Shared Convergence Functions
2
- # Common functions used by converge-task.ps1, sdd-check.ps1, and verify-patterns.ps1
3
- # Version: 1.0.1 - 2026-08-29
4
-
5
- function Get-SpecClauses {
6
- param(
7
- [Parameter(Mandatory=$true)]
8
- [string]$File
9
- )
10
-
11
- if (-not (Test-Path $File)) {
12
- Write-Error "SPEC file not found: $File"
13
- return @()
14
- }
15
-
16
- $content = Get-Content $File -Raw
17
- $clauses = @()
18
-
19
- # Match all clause patterns
20
- $patterns = @(
21
- '\[(SC-[A-Z0-9]+-[0-9]+)\]',
22
- '\[(SC-[0-9]+)\]',
23
- '\[(SC-COLOR-[0-9]+)\]',
24
- '\[(SC-DIM-[0-9]+)\]',
25
- '\[(AC-[A-Z0-9]+-[0-9]+)\]',
26
- '\[(AC-[0-9]+)\]'
27
- )
28
-
29
- foreach ($pattern in $patterns) {
30
- $matches = [regex]::Matches($content, $pattern)
31
- foreach ($m in $matches) {
32
- $id = $m.Groups[1].Value
33
- if ($id -notin $clauses.Id) {
34
- $context = Get-ClauseContext -File $File -ClauseId $id
35
- $clauses += @{
36
- Id = $id
37
- Type = Get-ClauseType -ClauseId $id
38
- Text = $context
39
- }
40
- }
41
- }
42
- }
43
-
44
- return $clauses
45
- }
46
-
47
- function Get-ClauseContext {
48
- param(
49
- [Parameter(Mandatory=$true)]
50
- [string]$File,
51
-
52
- [Parameter(Mandatory=$true)]
53
- [string]$ClauseId
54
- )
55
-
56
- $content = Get-Content $File -Raw
57
- # Match clause ID and get text on same line or next line
58
- $pattern = "(?i)\[$ClauseId\]\s*`?([^`\n]+)"
59
- $match = [regex]::Match($content, $pattern)
60
-
61
- if ($match.Success) {
62
- $text = $match.Groups[1].Value.Trim()
63
- # Remove markdown table characters
64
- $text = $text -replace '^\|', '' -replace '\|$', '' -replace '\|', ' '
65
- $text = $text -replace '\s+', ' '
66
- return $text.Substring(0, [Math]::Min(200, $text.Length))
67
- }
68
- return ""
69
- }
70
-
71
- function Get-ClauseType {
72
- param([string]$ClauseId)
73
-
74
- if ($ClauseId -match 'COLOR') { return "Color" }
75
- if ($ClauseId -match 'DIM') { return "Dimension" }
76
- if ($ClauseId -match 'AC-') { return "Acceptance" }
77
- return "Text"
78
- }
79
-
80
- function Get-ClauseSearchText {
81
- param([string]$ClauseText)
82
-
83
- $searchText = $ClauseText -replace '\[.*?\]', '' -replace '\(.*?\)', '' -replace '`', ''
84
- $searchText = $searchText.Trim()
85
-
86
- return $searchText
87
- }
88
-
89
- function Test-ClauseMatch {
90
- param(
91
- [Parameter(Mandatory=$true)]
92
- [string]$ClauseId,
93
-
94
- [string]$ClauseText,
95
-
96
- [string]$ClauseType,
97
-
98
- [string[]]$Files
99
- )
100
-
101
- if ($Files.Count -eq 0) {
102
- return @{
103
- ClauseId = $ClauseId
104
- Found = $null
105
- Location = "No implementation files"
106
- }
107
- }
108
-
109
- $searchText = Get-ClauseSearchText -ClauseText $ClauseText
110
-
111
- if ($searchText.Length -lt 2) {
112
- return @{
113
- ClauseId = $ClauseId
114
- Found = $null
115
- Location = "Text too short to search"
116
- }
117
- }
118
-
119
- if ($ClauseType -eq "Color") {
120
- return Test-ColorMatch -ClauseId $ClauseId -SearchText $searchText -Files $Files
121
- }
122
-
123
- return Test-TextMatch -ClauseId $ClauseId -SearchText $searchText -Files $Files
124
- }
125
-
126
- function Test-TextMatch {
127
- param(
128
- [string]$ClauseId,
129
- [string]$SearchText,
130
- [string[]]$Files
131
- )
132
-
133
- foreach ($file in $Files) {
134
- if (-not (Test-Path $file)) { continue }
135
- $content = Get-Content $file -Raw -ErrorAction SilentlyContinue
136
- if (-not $content) { continue }
137
-
138
- if ($content -match [regex]::Escape($SearchText)) {
139
- return @{
140
- ClauseId = $ClauseId
141
- Found = $true
142
- Location = $file
143
- Text = $SearchText
144
- }
145
- }
146
- }
147
-
148
- return @{
149
- ClauseId = $ClauseId
150
- Found = $false
151
- Location = "[Text not found]"
152
- Text = $SearchText
153
- }
154
- }
155
-
156
- function Test-ColorMatch {
157
- param(
158
- [string]$ClauseId,
159
- [string]$SearchText,
160
- [string[]]$Files
161
- )
162
-
163
- # Extract hex from search text
164
- $hexPattern = '#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\b'
165
- $specHex = ($SearchText -split '#')[-1] -replace '[^A-Fa-f0-9]', ''
166
-
167
- # Normalize 3-char hex to 6-char
168
- if ($specHex.Length -eq 3) {
169
- $specHex = $specHex[0] + $specHex[0] + $specHex[1] + $specHex[1] + $specHex[2] + $specHex[2]
170
- }
171
- $specHex = $specHex.ToUpper()
172
-
173
- foreach ($file in $Files) {
174
- if (-not (Test-Path $file)) { continue }
175
- $content = Get-Content $file -Raw -ErrorAction SilentlyContinue
176
- if (-not $content) { continue }
177
-
178
- $implHexes = [regex]::Matches($content, $hexPattern) | ForEach-Object {
179
- $h = $_.Groups[1].Value
180
- if ($h.Length -eq 3) {
181
- $h = $h[0] + $h[0] + $h[1] + $h[1] + $h[2] + $h[2]
182
- }
183
- $h.ToUpper()
184
- }
185
-
186
- if ("#$specHex" -in $implHexes) {
187
- return @{
188
- ClauseId = $ClauseId
189
- Found = $true
190
- Location = $file
191
- Text = $SearchText
192
- }
193
- }
194
- }
195
-
196
- return @{
197
- ClauseId = $ClauseId
198
- Found = $false
199
- Location = "[Color #$specHex not found]"
200
- Text = $SearchText
201
- }
202
- }
203
-
204
- function Get-TaskFiles {
205
- param(
206
- [string]$TaskId,
207
- [string]$TaskDir
208
- )
209
-
210
- if (-not $TaskDir) {
211
- $dirs = Get-ChildItem -Filter "task-*-*" -Directory -ErrorAction SilentlyContinue
212
- $TaskDir = ($dirs | Select-Object -First 1).Name
213
- }
214
-
215
- if (-not $TaskDir) { return @() }
216
-
217
- $pattern = "$TaskId-*.md"
218
- $files = Get-ChildItem -Path $TaskDir -Filter $pattern -ErrorAction SilentlyContinue
219
- $files = $files | Where-Object { $_.Name -ne "MASTER-TASKS.md" }
220
-
221
- if (-not $files) { return @() }
222
-
223
- # Extract files from task content
224
- $content = Get-Content $files[0].FullName -Raw
225
- $implFiles = @()
226
-
227
- # Match: - `path` or - [name](path)
228
- $lines = $content -split '\n'
229
- foreach ($line in $lines) {
230
- # Match `- `path` or `- [name](path)`
231
- if ($line -match '^\s*-\s+`([^`]+)`') {
232
- $implFiles += $Matches[1]
233
- } elseif ($line -match '^\s*-\s+\[[^\]]+\]\(([^)]+)\)') {
234
- $implFiles += $Matches[1]
235
- }
236
- }
237
-
238
- return $implFiles
239
- }
240
-
241
- function Write-ConvergeStatus {
242
- param(
243
- [Parameter(Mandatory=$true)]
244
- [string]$Symbol,
245
-
246
- [Parameter(Mandatory=$true)]
247
- [string]$Text,
248
-
249
- [ValidateSet("Pass", "Fail", "Warn", "Info", "Header", "White")]
250
- [string]$Color = "White"
251
- )
252
-
253
- $colors = @{
254
- "Pass" = "Green"
255
- "Fail" = "Red"
256
- "Warn" = "Yellow"
257
- "Info" = "Cyan"
258
- "Header" = "Magenta"
259
- "White" = "White"
260
- }
261
- $fg = if ($colors[$Color]) { $colors[$Color] } else { "White" }
262
- Write-Host "$Symbol $Text" -ForegroundColor $fg
263
- }
264
-
265
- function Write-ConvergeHeader {
266
- param([string]$Text)
267
-
268
- Write-Host ""
269
- Write-Host "--- $Text ---" -ForegroundColor Magenta
270
- }
@@ -1,208 +0,0 @@
1
- param(
2
- [string]$PatternRepo = "converge/patterns/pattern-repository.md",
3
- [string]$SrcDir = "src",
4
- [bool]$Report = $true
5
- )
6
-
7
- $ErrorActionPreference = "Continue"
8
-
9
- # Load pattern repository
10
- if (-not (Test-Path $PatternRepo)) {
11
- Write-Host "[WARN] Pattern repository not found: $PatternRepo" -ForegroundColor Yellow
12
- Write-Host "Creating default pattern repository..." -ForegroundColor Yellow
13
- New-Item -ItemType Directory -Path (Split-Path $PatternRepo -Parent) -Force | Out-Null
14
- Copy-Item -Path "templates/pattern-repository.md" -Destination $PatternRepo -Force -ErrorAction SilentlyContinue
15
- if (-not (Test-Path $PatternRepo)) {
16
- Write-Host "[FAIL] Could not create pattern repository" -ForegroundColor Red
17
- exit 1
18
- }
19
- }
20
-
21
- Write-Host ""
22
- Write-Host "========================================" -ForegroundColor Cyan
23
- Write-Host " SDD Pattern Verification" -ForegroundColor Cyan
24
- Write-Host "========================================" -ForegroundColor Cyan
25
- Write-Host ""
26
-
27
- # Parse patterns
28
- $content = Get-Content $PatternRepo -Raw
29
- $patternBlocks = [regex]::Matches($content, '(?s)\[PAT-(\d+)\](.*?)(?=\n### |\n## |\n---\Z)') | ForEach-Object {
30
- @{
31
- Id = "PAT-$($_.Groups[1].Value)"
32
- Block = $_.Groups[2].Value
33
- }
34
- }
35
-
36
- Write-Host "[INFO] Found $($patternBlocks.Count) patterns" -ForegroundColor Cyan
37
- Write-Host ""
38
-
39
- if ($patternBlocks.Count -eq 0) {
40
- Write-Host "[WARN] No patterns found in repository" -ForegroundColor Yellow
41
- Write-Host "Add patterns using [PAT-NNN] format" -ForegroundColor Yellow
42
- exit 0
43
- }
44
-
45
- # Get source files
46
- if (-not (Test-Path $SrcDir)) {
47
- Write-Host "[WARN] Source directory not found: $SrcDir" -ForegroundColor Yellow
48
- Write-Host "Searching in current directory..." -ForegroundColor Yellow
49
- $SrcDir = "."
50
- }
51
-
52
- $extensions = @("*.ts", "*.tsx", "*.js", "*.jsx", "*.cs", "*.py", "*.go", "*.java")
53
- $sourceFiles = Get-ChildItem -Path $SrcDir -Recurse -Include $extensions -File -ErrorAction SilentlyContinue
54
-
55
- Write-Host "[INFO] Source files: $($sourceFiles.Count)" -ForegroundColor Cyan
56
-
57
- # Verify patterns
58
- $results = @()
59
- $passCount = 0
60
- $failCount = 0
61
-
62
- foreach ($pattern in $patternBlocks) {
63
- Write-Host ""
64
- Write-Host "--- $($pattern.Id) ---" -ForegroundColor Magenta
65
-
66
- # Extract description
67
- if ($pattern.Block -match '(?s)\*\*Description:\*\*\s*(.*?)(?=\n\n|\n```)') {
68
- $desc = $Matches[1].Trim()
69
- $shortDesc = $desc.Substring(0, [Math]::Min(60, $desc.Length))
70
- Write-Host " $shortDesc" -ForegroundColor Gray
71
- }
72
-
73
- # Extract regex pattern
74
- $regex = $null
75
- if ($pattern.Block -match 'Regex for verification:\s*```\s*([\s\S]*?)\s*```') {
76
- $regex = $Matches[1].Trim()
77
- }
78
-
79
- if (-not $regex) {
80
- Write-Host "[WARN] No regex defined for $($pattern.Id)" -ForegroundColor Yellow
81
- continue
82
- }
83
-
84
- # Search for violations
85
- $violations = @()
86
- foreach ($file in $sourceFiles) {
87
- $fileContent = Get-Content $file.FullName -Raw -ErrorAction SilentlyContinue
88
- if (-not $fileContent) { continue }
89
-
90
- try {
91
- if ($fileContent -match $regex) {
92
- $match = $Matches[0]
93
- # Check if it is a compliant example
94
- $line = ($fileContent -split '\n' | Where-Object { $_ -match [regex]::Escape($match) } | Select-Object -First 1)
95
- if ($line -and $line -notmatch "// Pattern: \[$($pattern.Id)\]") {
96
- $violations += @{
97
- File = $file.FullName -replace [regex]::Escape($PWD), '.'
98
- Match = $match.Substring(0, [Math]::Min(80, $match.Length))
99
- }
100
- }
101
- }
102
- } catch {
103
- # Skip invalid regex
104
- }
105
- }
106
-
107
- if ($violations.Count -eq 0) {
108
- Write-Host "[PASS] $($pattern.Id): No violations" -ForegroundColor Green
109
- $passCount++
110
- $results += @{
111
- Pattern = $pattern.Id
112
- Status = "Pass"
113
- Violations = 0
114
- }
115
- } else {
116
- Write-Host "[FAIL] $($pattern.Id): $($violations.Count) violation(s)" -ForegroundColor Red
117
- foreach ($v in $violations | Select-Object -First 3) {
118
- Write-Host " -> $($v.File)" -ForegroundColor Red
119
- Write-Host " $($v.Match)" -ForegroundColor DarkGray
120
- }
121
- if ($violations.Count -gt 3) {
122
- Write-Host " ... and $($violations.Count - 3) more" -ForegroundColor Yellow
123
- }
124
- $failCount++
125
- $results += @{
126
- Pattern = $pattern.Id
127
- Status = "Fail"
128
- Violations = $violations.Count
129
- }
130
- }
131
- }
132
-
133
- # Summary
134
- Write-Host ""
135
- Write-Host "========================================" -ForegroundColor Cyan
136
- Write-Host " Pattern Verification Summary" -ForegroundColor Cyan
137
- Write-Host "========================================" -ForegroundColor Cyan
138
- Write-Host ""
139
- Write-Host " Patterns Checked: $($patternBlocks.Count)" -ForegroundColor Gray
140
- Write-Host " Passed: $passCount" -ForegroundColor Green
141
- Write-Host " Failed: $failCount" -ForegroundColor $(if ($failCount -gt 0) { "Red" } else { "Green" })
142
- Write-Host ""
143
-
144
- # Generate report
145
- if ($Report) {
146
- $reportDir = "converge/patterns"
147
- if (-not (Test-Path $reportDir)) {
148
- New-Item -ItemType Directory -Path $reportDir -Force | Out-Null
149
- }
150
-
151
- $reportFile = Join-Path $reportDir "verification-$(Get-Date -Format 'yyyy-MM-dd').md"
152
-
153
- # Calculate pass rate safely
154
- $totalPatterns = $patternBlocks.Count
155
- $passRate = if ($totalPatterns -gt 0) { [Math]::Round(($passCount / $totalPatterns) * 100, 1) } else { 0 }
156
-
157
- $report = @"
158
- # Pattern Verification Report
159
-
160
- Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
161
-
162
- ## Summary
163
-
164
- | Metric | Value |
165
- |--------|-------|
166
- | Patterns Checked | $totalPatterns |
167
- | Passed | $passCount |
168
- | Failed | $failCount |
169
- | Pass Rate | $passRate% |
170
-
171
- ## Results
172
-
173
- | Pattern | Status | Violations |
174
- |---------|--------|------------|
175
- "@
176
-
177
- foreach ($r in $results) {
178
- $status = if ($r.Status -eq "Pass") { "PASS" } else { "FAIL" }
179
- $report += "`n| $($r.Pattern) | $status | $($r.Violations) |"
180
- }
181
-
182
- $report += @"
183
-
184
- ## Failed Patterns
185
-
186
- "@
187
-
188
- $failedResults = $results | Where-Object { $_.Status -eq "Fail" }
189
- if ($failedResults.Count -eq 0) {
190
- $report += "`n_No violations found._"
191
- } else {
192
- foreach ($f in $failedResults) {
193
- $report += "`n### $($f.Pattern)`n`nViolations: $($f.Violations)`n"
194
- }
195
- }
196
-
197
- $report += @"
198
-
199
- ---
200
- Generated by SDD Pattern Verification
201
- "@
202
-
203
- $report | Out-File -FilePath $reportFile -Encoding UTF8
204
- Write-Host "[INFO] Report saved: $reportFile" -ForegroundColor Cyan
205
- }
206
-
207
- # Exit code
208
- exit $(if ($failCount -eq 0) { 0 } else { 1 })