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.
@@ -1,461 +0,0 @@
1
- # SDD Output Directory Management
2
- # Centralized helpers for managing output file locations
3
- # Version: 1.0.0 - 2026-08-29
4
-
5
- $ErrorActionPreference = "Stop"
6
-
7
- # ============================================================
8
- # Configuration
9
- # ============================================================
10
-
11
- # Default output base directory
12
- $script:SDD_OUTPUT_BASE = "sdd"
13
-
14
- # Subdirectories per phase
15
- $script:SDD_DIRS = @{
16
- Brief = "" # sdd/brief.md (root of sdd/)
17
- Spec = "" # sdd/SPEC.md (root of sdd/)
18
- Tasks = "tasks" # sdd/tasks/
19
- Converge = "converge" # sdd/converge/
20
- Plans = "plans" # sdd/plans/
21
- }
22
-
23
- # Legacy locations (for migration detection)
24
- $script:LEGACY_FILES = @{
25
- Brief = "BMAD-brief.md"
26
- Spec = "SPEC.md"
27
- }
28
-
29
- # ============================================================
30
- # Core Functions
31
- # ============================================================
32
-
33
- function Get-SddOutputBase {
34
- <#
35
- .SYNOPSIS
36
- Get the SDD output base directory, defaulting to 'sdd/'
37
- #>
38
- param(
39
- [string]$BaseDir = ""
40
- )
41
-
42
- if ($BaseDir -and $BaseDir -ne "") {
43
- return $BaseDir
44
- }
45
-
46
- # Check config for custom output directory
47
- if (Test-Path ".sdd/config.json") {
48
- try {
49
- $config = Get-Content ".sdd/config.json" -Raw | ConvertFrom-Json
50
- if ($config.output -and $config.output.baseDir) {
51
- return $config.output.baseDir
52
- }
53
- } catch {
54
- # Ignore config errors
55
- }
56
- }
57
-
58
- return $script:SDD_OUTPUT_BASE
59
- }
60
-
61
- function Get-SddOutputPath {
62
- <#
63
- .SYNOPSIS
64
- Get full path to an SDD output file
65
-
66
- .PARAMETER Type
67
- Output type: Brief, Spec, Tasks, Converge, Plans
68
-
69
- .PARAMETER SubPath
70
- Optional subpath within the output directory
71
- #>
72
- param(
73
- [Parameter(Mandatory=$true)]
74
- [ValidateSet("Brief", "Spec", "Tasks", "Converge", "Plans")]
75
- [string]$Type,
76
-
77
- [string]$SubPath = ""
78
- )
79
-
80
- $base = Get-SddOutputBase
81
- $subDir = $script:SDD_DIRS[$Type]
82
-
83
- $path = $base
84
- if ($subDir) {
85
- $path = Join-Path $path $subDir
86
- }
87
- if ($SubPath) {
88
- $path = Join-Path $path $SubPath
89
- }
90
-
91
- return $path
92
- }
93
-
94
- function Initialize-SddOutputDirs {
95
- <#
96
- .SYNOPSIS
97
- Create all SDD output directories if they don't exist
98
- #>
99
- param(
100
- [string]$BaseDir = ""
101
- )
102
-
103
- $base = Get-SddOutputBase -BaseDir $BaseDir
104
- $created = @()
105
-
106
- # Create base directory
107
- if (-not (Test-Path $base)) {
108
- New-Item -ItemType Directory -Path $base -Force | Out-Null
109
- $created += $base
110
- }
111
-
112
- # Create subdirectories
113
- foreach ($dir in $script:SDD_DIRS.Values) {
114
- if ($dir) {
115
- $fullPath = Join-Path $base $dir
116
- if (-not (Test-Path $fullPath)) {
117
- New-Item -ItemType Directory -Path $fullPath -Force | Out-Null
118
- $created += $fullPath
119
- }
120
- }
121
- }
122
-
123
- return $created
124
- }
125
-
126
- function Test-SddOutputInitialized {
127
- <#
128
- .SYNOPSIS
129
- Check if SDD output directories exist
130
- #>
131
- param(
132
- [string]$BaseDir = ""
133
- )
134
-
135
- $base = Get-SddOutputBase -BaseDir $BaseDir
136
- return Test-Path $base
137
- }
138
-
139
- function Get-LegacyFiles {
140
- <#
141
- .SYNOPSIS
142
- Find legacy files in project root that should be migrated
143
- #>
144
- param([switch]$Detailed)
145
-
146
- $found = @{}
147
-
148
- foreach ($name in $script:LEGACY_FILES.Keys) {
149
- $path = $script:LEGACY_FILES[$name]
150
- if (Test-Path $path) {
151
- if ($Detailed) {
152
- $found[$name] = @{
153
- LegacyPath = $path
154
- NewPath = Get-SddOutputPath -Type $name
155
- Exists = $true
156
- }
157
- } else {
158
- $found[$name] = $path
159
- }
160
- }
161
- }
162
-
163
- return $found
164
- }
165
-
166
- function Move-LegacyFile {
167
- <#
168
- .SYNOPSIS
169
- Move a legacy file to new output directory
170
- #>
171
- param(
172
- [Parameter(Mandatory=$true)]
173
- [ValidateSet("Brief", "Spec")]
174
- [string]$Type,
175
-
176
- [switch]$Force
177
- )
178
-
179
- $legacyPath = $script:LEGACY_FILES[$Type]
180
- if (-not (Test-Path $legacyPath)) {
181
- Write-Verbose "No legacy file found for $Type"
182
- return $false
183
- }
184
-
185
- $newPath = Get-SddOutputPath -Type $Type
186
-
187
- # Check if new path already exists
188
- if ((Test-Path $newPath) -and -not $Force) {
189
- Write-Warning "New file already exists: $newPath"
190
- Write-Host "Use -Force to overwrite" -ForegroundColor Yellow
191
- return $false
192
- }
193
-
194
- # Initialize directories
195
- $base = Get-SddOutputBase
196
- $subDir = $script:SDD_DIRS[$Type]
197
- if ($subDir) {
198
- $targetDir = Join-Path $base $subDir
199
- } else {
200
- $targetDir = $base
201
- }
202
- if (-not (Test-Path $targetDir)) {
203
- New-Item -ItemType Directory -Path $targetDir -Force | Out-Null
204
- }
205
-
206
- # Move file
207
- Move-Item -Path $legacyPath -Destination $newPath -Force
208
- Write-Host "[MIGRATED] $legacyPath -> $newPath" -ForegroundColor Green
209
-
210
- return $true
211
- }
212
-
213
- function Migrate-AllLegacyFiles {
214
- <#
215
- .SYNOPSIS
216
- Migrate all legacy files to new output directory structure
217
- #>
218
- param(
219
- [switch]$DryRun,
220
- [switch]$Force
221
- )
222
-
223
- $legacy = Get-LegacyFiles -Detailed
224
-
225
- if ($legacy.Count -eq 0) {
226
- Write-Host "No legacy files to migrate" -ForegroundColor Green
227
- return
228
- }
229
-
230
- Write-Host ""
231
- Write-Host "=== Legacy File Migration ===" -ForegroundColor Cyan
232
- Write-Host ""
233
- Write-Host "Found $($legacy.Count) legacy file(s):" -ForegroundColor Yellow
234
- Write-Host ""
235
-
236
- foreach ($name in $legacy.Keys) {
237
- $info = $legacy[$name]
238
- Write-Host " $name :" -ForegroundColor Gray
239
- Write-Host " Legacy: $($info.LegacyPath)" -ForegroundColor White
240
- Write-Host " New: $($info.NewPath)" -ForegroundColor White
241
- Write-Host ""
242
- }
243
-
244
- if ($DryRun) {
245
- Write-Host "[DRY RUN] No files were moved" -ForegroundColor Yellow
246
- return
247
- }
248
-
249
- $confirm = Read-Host "Proceed with migration? (y/N)"
250
- if ($confirm -ne "y" -and $confirm -ne "Y") {
251
- Write-Host "Migration cancelled" -ForegroundColor Yellow
252
- return
253
- }
254
-
255
- Write-Host ""
256
- Write-Host "Migrating files..." -ForegroundColor Cyan
257
-
258
- foreach ($name in $legacy.Keys) {
259
- Move-LegacyFile -Type $name -Force:$Force
260
- }
261
-
262
- Write-Host ""
263
- Write-Host "[OK] Migration complete" -ForegroundColor Green
264
- }
265
-
266
- function Get-SddStructure {
267
- <#
268
- .SYNOPSIS
269
- Get the current SDD output structure as a tree
270
- #>
271
- param(
272
- [string]$BaseDir = "",
273
- [switch]$IncludeEmpty
274
- )
275
-
276
- $base = Get-SddOutputBase -BaseDir $BaseDir
277
- $structure = @{
278
- Base = $base
279
- Exists = Test-Path $base
280
- Brief = $null
281
- Spec = $null
282
- Tasks = @()
283
- Converge = @()
284
- Plans = @()
285
- }
286
-
287
- if (-not $structure.Exists) {
288
- return $structure
289
- }
290
-
291
- # Check brief
292
- $briefPath = Get-SddOutputPath -Type Brief
293
- if (Test-Path $briefPath) {
294
- $structure.Brief = @{
295
- Path = $briefPath
296
- Modified = (Get-Item $briefPath).LastWriteTime
297
- }
298
- }
299
-
300
- # Check spec
301
- $specPath = Get-SddOutputPath -Type Spec
302
- if (Test-Path $specPath) {
303
- $structure.Spec = @{
304
- Path = $specPath
305
- Modified = (Get-Item $specPath).LastWriteTime
306
- }
307
- }
308
-
309
- # Check tasks directory
310
- $tasksPath = Get-SddOutputPath -Type Tasks
311
- if (Test-Path $tasksPath) {
312
- $taskDirs = Get-ChildItem -Path $tasksPath -Directory -ErrorAction SilentlyContinue
313
- foreach ($dir in $taskDirs) {
314
- $masterPath = Join-Path $dir.FullName "MASTER-TASKS.md"
315
- $taskFiles = Get-ChildItem -Path $dir.FullName -Filter "T-*.md" -File -ErrorAction SilentlyContinue
316
- $taskFiles = $taskFiles | Where-Object { $_.Name -ne "MASTER-TASKS.md" }
317
-
318
- $structure.Tasks += @{
319
- Name = $dir.Name
320
- Path = $dir.FullName
321
- Modified = $dir.LastWriteTime
322
- HasMaster = Test-Path $masterPath
323
- TaskCount = $taskFiles.Count
324
- }
325
- }
326
- }
327
-
328
- # Check converge directory
329
- $convergePath = Get-SddOutputPath -Type Converge
330
- if (Test-Path $convergePath) {
331
- $files = Get-ChildItem -Path $convergePath -File -ErrorAction SilentlyContinue
332
- $structure.Converge = $files | ForEach-Object {
333
- @{
334
- Name = $_.Name
335
- Path = $_.FullName
336
- Modified = $_.LastWriteTime
337
- }
338
- }
339
- }
340
-
341
- return $structure
342
- }
343
-
344
- function Show-SddStructure {
345
- <#
346
- .SYNOPSIS
347
- Display SDD output structure as a tree
348
- #>
349
- param([string]$BaseDir = "")
350
-
351
- $structure = Get-SddStructure -BaseDir $BaseDir
352
-
353
- Write-Host ""
354
- Write-Host "=== SDD Output Structure ===" -ForegroundColor Cyan
355
- Write-Host ""
356
-
357
- if (-not $structure.Exists) {
358
- Write-Host " $($structure.Base)/ (not initialized)" -ForegroundColor Gray
359
- Write-Host ""
360
- Write-Host " Run /sdd init to create the structure" -ForegroundColor Yellow
361
- return
362
- }
363
-
364
- # Brief
365
- $briefIcon = if ($structure.Brief) { "[V]" } else { "[ ]" }
366
- $briefColor = if ($structure.Brief) { "Green" } else { "Gray" }
367
- Write-Host " $($briefIcon) $($structure.Base)/brief.md" -ForegroundColor $briefColor
368
-
369
- # Spec
370
- $specIcon = if ($structure.Spec) { "[V]" } else { "[ ]" }
371
- $specColor = if ($structure.Spec) { "Green" } else { "Gray" }
372
- Write-Host " $($specIcon) $($structure.Base)/SPEC.md" -ForegroundColor $specColor
373
-
374
- # Tasks
375
- Write-Host " [ ] $($structure.Base)/tasks/" -ForegroundColor Gray
376
- if ($structure.Tasks.Count -gt 0) {
377
- foreach ($task in $structure.Tasks) {
378
- $status = if ($task.HasMaster) { "[V]" } else { "[ ]" }
379
- Write-Host " $($status) $($task.Name)/" -ForegroundColor Gray
380
- Write-Host " MASTER-TASKS.md ($($task.TaskCount) tasks)" -ForegroundColor DarkGray
381
- }
382
- } else {
383
- Write-Host " (no task directories)" -ForegroundColor DarkGray
384
- }
385
-
386
- # Converge
387
- Write-Host " [ ] $($structure.Base)/converge/" -ForegroundColor Gray
388
- if ($structure.Converge.Count -gt 0) {
389
- foreach ($file in $structure.Converge) {
390
- Write-Host " [V] $($file.Name)" -ForegroundColor Green
391
- }
392
- } else {
393
- Write-Host " (no converge reports)" -ForegroundColor DarkGray
394
- }
395
-
396
- Write-Host ""
397
- }
398
-
399
- # ============================================================
400
- # Config Helpers
401
- # ============================================================
402
-
403
- function Set-SddOutputConfig {
404
- <#
405
- .SYNOPSIS
406
- Update .sdd/config.json with output directory paths
407
- #>
408
- param(
409
- [string]$BaseDir = ""
410
- )
411
-
412
- $base = Get-SddOutputBase -BaseDir $BaseDir
413
-
414
- if (Test-Path ".sdd/config.json") {
415
- $config = Get-Content ".sdd/config.json" -Raw | ConvertFrom-Json
416
-
417
- # Add output section
418
- $config | Add-Member -NotePropertyName "output" -NotePropertyValue ([ordered]@{
419
- baseDir = $base
420
- brief = Get-SddOutputPath -Type Brief
421
- spec = Get-SddOutputPath -Type Spec
422
- tasks = Get-SddOutputPath -Type Tasks
423
- converge = Get-SddOutputPath -Type Converge
424
- }) -Force
425
-
426
- $config | ConvertTo-Json | Set-Content ".sdd/config.json"
427
- }
428
- }
429
-
430
- function Get-SddOutputConfig {
431
- <#
432
- .SYNOPSIS
433
- Get output paths from config
434
- #>
435
- if (Test-Path ".sdd/config.json") {
436
- $config = Get-Content ".sdd/config.json" -Raw | ConvertFrom-Json
437
- if ($config.output) {
438
- return $config.output
439
- }
440
- }
441
- return $null
442
- }
443
-
444
- # ============================================================
445
- # Export for use in other scripts
446
- # ============================================================
447
-
448
- # When dot-sourced, return functions
449
- return @{
450
- GetBase = ${function:Get-SddOutputBase}
451
- GetPath = ${function:Get-SddOutputPath}
452
- Init = ${function:Initialize-SddOutputDirs}
453
- TestInit = ${function:Test-SddOutputInitialized}
454
- GetLegacy = ${function:Get-LegacyFiles}
455
- MoveLegacy = ${function:Move-LegacyFile}
456
- MigrateAll = ${function:Migrate-AllLegacyFiles}
457
- GetStructure = ${function:Get-SddStructure}
458
- ShowStructure = ${function:Show-SddStructure}
459
- SetConfig = ${function:Set-SddOutputConfig}
460
- GetConfig = ${function:Get-SddOutputConfig}
461
- }
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 })