specpulse 1.0.6__py3-none-any.whl → 1.1.0__py3-none-any.whl

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.
Files changed (43) hide show
  1. specpulse/__init__.py +1 -1
  2. specpulse/cli/main.py +598 -617
  3. specpulse/core/specpulse.py +1110 -1105
  4. specpulse/resources/commands/claude/sp-continue.md +203 -0
  5. specpulse/resources/commands/claude/{plan.md → sp-plan.md} +53 -38
  6. specpulse/resources/commands/claude/sp-pulse.md +142 -0
  7. specpulse/resources/commands/claude/{spec.md → sp-spec.md} +36 -23
  8. specpulse/resources/commands/claude/sp-status.md +170 -0
  9. specpulse/resources/commands/claude/{task.md → sp-task.md} +68 -48
  10. specpulse/resources/commands/gemini/sp-continue.toml +56 -0
  11. specpulse/resources/commands/gemini/sp-plan.toml +68 -0
  12. specpulse/resources/commands/gemini/{pulse.toml → sp-pulse.toml} +12 -6
  13. specpulse/resources/commands/gemini/sp-spec.toml +54 -0
  14. specpulse/resources/commands/gemini/sp-status.toml +61 -0
  15. specpulse/resources/commands/gemini/sp-task.toml +79 -0
  16. specpulse/resources/memory/constitution.md +5 -5
  17. specpulse/resources/memory/context.md +12 -1
  18. specpulse/resources/scripts/{pulse-init.py → sp-pulse-init.py} +6 -6
  19. specpulse/resources/scripts/{pulse-init.sh → sp-pulse-init.sh} +95 -95
  20. specpulse/resources/scripts/{pulse-plan.py → sp-pulse-plan.py} +32 -7
  21. specpulse/resources/scripts/{pulse-plan.sh → sp-pulse-plan.sh} +136 -126
  22. specpulse/resources/scripts/{pulse-spec.py → sp-pulse-spec.py} +26 -6
  23. specpulse/resources/scripts/{pulse-spec.sh → sp-pulse-spec.sh} +126 -103
  24. specpulse/resources/scripts/{pulse-task.py → sp-pulse-task.py} +42 -6
  25. specpulse/resources/scripts/{pulse-task.sh → sp-pulse-task.sh} +32 -16
  26. specpulse/resources/templates/plan.md +206 -206
  27. specpulse/resources/templates/spec.md +125 -125
  28. specpulse/resources/templates/task.md +164 -163
  29. {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/METADATA +35 -35
  30. specpulse-1.1.0.dist-info/RECORD +41 -0
  31. specpulse/resources/commands/claude/pulse.md +0 -91
  32. specpulse/resources/commands/gemini/plan.toml +0 -59
  33. specpulse/resources/commands/gemini/spec.toml +0 -45
  34. specpulse/resources/commands/gemini/task.toml +0 -69
  35. specpulse/resources/scripts/pulse-init.ps1 +0 -186
  36. specpulse/resources/scripts/pulse-plan.ps1 +0 -251
  37. specpulse/resources/scripts/pulse-spec.ps1 +0 -185
  38. specpulse/resources/scripts/pulse-task.ps1 +0 -263
  39. specpulse-1.0.6.dist-info/RECORD +0 -41
  40. {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/WHEEL +0 -0
  41. {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/entry_points.txt +0 -0
  42. {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/licenses/LICENSE +0 -0
  43. {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/top_level.txt +0 -0
@@ -1,251 +0,0 @@
1
- # SpecPulse Plan Generation Script
2
- # Cross-platform PowerShell equivalent of pulse-plan.sh
3
-
4
- param(
5
- [Parameter(Mandatory=$true)]
6
- [string]$FeatureDir,
7
-
8
- [string]$PlanContent = ""
9
- )
10
-
11
- $ErrorActionPreference = "Stop"
12
- $ProgressPreference = "SilentlyContinue"
13
-
14
- # Configuration
15
- $ScriptName = $MyInvocation.MyCommand.Name
16
- $ProjectRoot = $PSScriptRoot | Split-Path -Parent | Split-Path -Parent
17
- $MemoryDir = Join-Path $ProjectRoot "memory"
18
- $ContextFile = Join-Path $MemoryDir "context.md"
19
- $TemplatesDir = Join-Path $ProjectRoot "resources" "templates"
20
-
21
- function Write-Log {
22
- param([string]$Message)
23
- $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
24
- Write-Host "[$Timestamp] $ScriptName : $Message" -ForegroundColor Yellow
25
- }
26
-
27
- function Exit-WithError {
28
- param([string]$Message)
29
- Write-Log "ERROR: $Message"
30
- exit 1
31
- }
32
-
33
- function Sanitize-FeatureDir {
34
- param([string]$Dir)
35
-
36
- if ([string]::IsNullOrWhiteSpace($Dir)) {
37
- Exit-WithError "Feature directory cannot be empty"
38
- }
39
-
40
- # Remove non-alphanumeric characters except hyphens and underscores
41
- $Sanitized = $Dir -replace '[^a-zA-Z0-9_-]', ''
42
-
43
- if ([string]::IsNullOrWhiteSpace($Sanitized)) {
44
- Exit-WithError "Invalid feature directory: '$Dir'"
45
- }
46
-
47
- return $Sanitized
48
- }
49
-
50
- function Find-FeatureDirectory {
51
- if (-not (Test-Path $ContextFile)) {
52
- Exit-WithError "No context file found and no feature directory provided"
53
- }
54
-
55
- try {
56
- $Content = Get-Content $ContextFile -Raw -Encoding UTF8
57
- # Look for "Active Feature" section
58
- if ($Content -match 'Active Feature:\s*(.+)') {
59
- $FeatureDir = $matches[1].Trim()
60
- Write-Log "Using active feature from context: $FeatureDir"
61
- return $FeatureDir
62
- } else {
63
- Exit-WithError "No active feature found in context file"
64
- }
65
- } catch {
66
- Exit-WithError "Failed to read context file: $_"
67
- }
68
- }
69
-
70
- function Get-CurrentFeatureDir {
71
- param([string]$ProvidedDir)
72
-
73
- if ($ProvidedDir) {
74
- return Sanitize-FeatureDir -Dir $ProvidedDir
75
- } else {
76
- return Find-FeatureDirectory
77
- }
78
- }
79
-
80
- function Validate-PlanStructure {
81
- param([string]$PlanFile)
82
-
83
- if (-not (Test-Path $PlanFile)) {
84
- Exit-WithError "Plan file does not exist: $PlanFile"
85
- }
86
-
87
- # Required sections
88
- $RequiredSections = @(
89
- "# Implementation Plan:",
90
- "## Technology Stack",
91
- "## Architecture Overview",
92
- "## Implementation Phases"
93
- )
94
-
95
- $Content = Get-Content $PlanFile -Raw -Encoding UTF8
96
- $MissingSections = @()
97
-
98
- foreach ($Section in $RequiredSections) {
99
- if ($Content -notmatch [regex]::Escape($Section)) {
100
- $MissingSections += $Section
101
- }
102
- }
103
-
104
- if ($MissingSections.Count -gt 0) {
105
- Write-Log "WARNING: Missing required sections: $($MissingSections -join ', ')"
106
- }
107
-
108
- return $MissingSections.Count
109
- }
110
-
111
- function Check-ConstitutionalGates {
112
- param([string]$PlanFile)
113
-
114
- if (-not (Test-Path $PlanFile)) {
115
- Exit-WithError "Plan file does not exist: $PlanFile"
116
- }
117
-
118
- $Content = Get-Content $PlanFile -Raw -Encoding UTF8
119
- $GatesStatus = @{}
120
-
121
- # Check for constitutional gates compliance
122
- $Gates = @{
123
- "Simplicity Gate" = "Article VII: Simplicity Gate"
124
- "Anti-Abstraction Gate" = "Article VII: Anti-Abstraction Gate"
125
- "Test-First Gate" = "Article III: Test-First Gate"
126
- "Integration-First Gate" = "Article VIII: Integration-First Gate"
127
- "Research Gate" = "Article VI: Research Gate"
128
- }
129
-
130
- foreach ($Gate in $Gates.GetEnumerator()) {
131
- if ($Content -match $Gate.Value) {
132
- $GatesStatus[$Gate.Key] = "COMPLETED"
133
- } else {
134
- $GatesStatus[$Gate.Key] = "PENDING"
135
- }
136
- }
137
-
138
- return $GatesStatus
139
- }
140
-
141
- function Analyze-Complexity {
142
- param([string]$PlanFile)
143
-
144
- if (-not (Test-Path $PlanFile)) {
145
- Exit-WithError "Plan file does not exist: $PlanFile"
146
- }
147
-
148
- $Content = Get-Content $PlanFile -Raw -Encoding UTF8
149
-
150
- # Count complexity exceptions
151
- $ExceptionMatches = [regex]::Matches($Content, "Complexity Exception")
152
- $ExceptionCount = $ExceptionMatches.Count
153
-
154
- # Check for complexity tracking
155
- $HasComplexityTracking = $Content -match "Complexity Tracking"
156
-
157
- # Count modules/projects mentioned
158
- $ModuleMatches = [regex]::Matches($Content, "(?i)(module|project)s?\s*[:\-]?\s*\d+")
159
- $ModuleCount = 0
160
- if ($ModuleMatches.Count -gt 0) {
161
- foreach ($Match in $ModuleMatches) {
162
- if ($Match.Value -match "\d+") {
163
- $ModuleCount = [int]$matches[0]
164
- break
165
- }
166
- }
167
- }
168
-
169
- return @{
170
- ExceptionCount = $ExceptionCount
171
- HasComplexityTracking = $HasComplexityTracking
172
- ModuleCount = $ModuleCount
173
- }
174
- }
175
-
176
- # Main execution
177
- Write-Log "Processing plan..."
178
-
179
- # Get and sanitize feature directory
180
- $SanitizedDir = Get-CurrentFeatureDir -ProvidedDir $FeatureDir
181
-
182
- # Set file paths
183
- $PlanFile = Join-Path $ProjectRoot "plans" $SanitizedDir "plan.md"
184
- $SpecFile = Join-Path $ProjectRoot "specs" $SanitizedDir "spec.md"
185
- $TemplateFile = Join-Path $TemplatesDir "plan.md"
186
-
187
- # Ensure plans directory exists
188
- $PlanDir = Split-Path $PlanFile -Parent
189
- New-Item -ItemType Directory -Path $PlanDir -Force | Out-Null
190
-
191
- # Handle plan content
192
- if ($PlanContent) {
193
- Write-Log "Updating plan file: $PlanFile"
194
- try {
195
- Set-Content -Path $PlanFile -Value $PlanContent -Encoding UTF8
196
- } catch {
197
- Exit-WithError "Failed to write plan content: $_"
198
- }
199
- } else {
200
- # Ensure plan file exists from template
201
- if (-not (Test-Path $PlanFile)) {
202
- if (-not (Test-Path $TemplateFile)) {
203
- Exit-WithError "Template not found: $TemplateFile"
204
- }
205
-
206
- Write-Log "Creating plan file from template: $PlanFile"
207
- try {
208
- Copy-Item $TemplateFile $PlanFile -Force
209
- } catch {
210
- Exit-WithError "Failed to copy plan template: $_"
211
- }
212
- } else {
213
- Write-Log "Plan file already exists: $PlanFile"
214
- }
215
- }
216
-
217
- # Validate plan structure
218
- Write-Log "Validating plan structure..."
219
- $MissingSections = Validate-PlanStructure -PlanFile $PlanFile
220
-
221
- # Check constitutional gates
222
- Write-Log "Checking constitutional gates..."
223
- $GatesStatus = Check-ConstitutionalGates -PlanFile $PlanFile
224
-
225
- # Analyze complexity
226
- Write-Log "Analyzing complexity..."
227
- $ComplexityAnalysis = Analyze-Complexity -PlanFile $PlanFile
228
-
229
- # Count completed constitutional gates
230
- $CompletedGates = 0
231
- foreach ($Status in $GatesStatus.Values) {
232
- if ($Status -eq "COMPLETED") {
233
- $CompletedGates++
234
- }
235
- }
236
-
237
- # Check if specification exists
238
- $SpecExists = Test-Path $SpecFile
239
-
240
- Write-Log "Plan processing completed successfully"
241
-
242
- # Output results
243
- Write-Host "PLAN_FILE=$PlanFile"
244
- Write-Host "SPEC_EXISTS=$SpecExists"
245
- Write-Host "MISSING_SECTIONS=$MissingSections"
246
- Write-Host "COMPLETED_GATES=$CompletedGates"
247
- Write-Host "TOTAL_GATES=$($GatesStatus.Count)"
248
- Write-Host "COMPLEXITY_EXCEPTIONS=$($ComplexityAnalysis.ExceptionCount)"
249
- Write-Host "HAS_COMPLEXITY_TRACKING=$($ComplexityAnalysis.HasComplexityTracking)"
250
- Write-Host "MODULE_COUNT=$($ComplexityAnalysis.ModuleCount)"
251
- Write-Host "STATUS=processed"
@@ -1,185 +0,0 @@
1
- # SpecPulse Specification Generation Script
2
- # Cross-platform PowerShell equivalent of pulse-spec.sh
3
-
4
- param(
5
- [Parameter(Mandatory=$true)]
6
- [string]$FeatureDir,
7
-
8
- [string]$SpecContent = ""
9
- )
10
-
11
- $ErrorActionPreference = "Stop"
12
- $ProgressPreference = "SilentlyContinue"
13
-
14
- # Configuration
15
- $ScriptName = $MyInvocation.MyCommand.Name
16
- $ProjectRoot = $PSScriptRoot | Split-Path -Parent | Split-Path -Parent
17
- $MemoryDir = Join-Path $ProjectRoot "memory"
18
- $ContextFile = Join-Path $MemoryDir "context.md"
19
- $TemplatesDir = Join-Path $ProjectRoot "resources" "templates"
20
-
21
- function Write-Log {
22
- param([string]$Message)
23
- $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
24
- Write-Host "[$Timestamp] $ScriptName : $Message" -ForegroundColor Yellow
25
- }
26
-
27
- function Exit-WithError {
28
- param([string]$Message)
29
- Write-Log "ERROR: $Message"
30
- exit 1
31
- }
32
-
33
- function Sanitize-FeatureDir {
34
- param([string]$Dir)
35
-
36
- if ([string]::IsNullOrWhiteSpace($Dir)) {
37
- Exit-WithError "Feature directory cannot be empty"
38
- }
39
-
40
- # Remove non-alphanumeric characters except hyphens and underscores
41
- $Sanitized = $Dir -replace '[^a-zA-Z0-9_-]', ''
42
-
43
- if ([string]::IsNullOrWhiteSpace($Sanitized)) {
44
- Exit-WithError "Invalid feature directory: '$Dir'"
45
- }
46
-
47
- return $Sanitized
48
- }
49
-
50
- function Find-FeatureDirectory {
51
- if (-not (Test-Path $ContextFile)) {
52
- Exit-WithError "No context file found and no feature directory provided"
53
- }
54
-
55
- try {
56
- $Content = Get-Content $ContextFile -Raw -Encoding UTF8
57
- # Look for "Active Feature" section
58
- if ($Content -match 'Active Feature:\s*(.+)') {
59
- $FeatureDir = $matches[1].Trim()
60
- Write-Log "Using active feature from context: $FeatureDir"
61
- return $FeatureDir
62
- } else {
63
- Exit-WithError "No active feature found in context file"
64
- }
65
- } catch {
66
- Exit-WithError "Failed to read context file: $_"
67
- }
68
- }
69
-
70
- function Get-CurrentFeatureDir {
71
- param([string]$ProvidedDir)
72
-
73
- if ($ProvidedDir) {
74
- return Sanitize-FeatureDir -Dir $ProvidedDir
75
- } else {
76
- return Find-FeatureDirectory
77
- }
78
- }
79
-
80
- function Validate-Specification {
81
- param([string]$SpecFile)
82
-
83
- if (-not (Test-Path $SpecFile)) {
84
- Exit-WithError "Specification file does not exist: $SpecFile"
85
- }
86
-
87
- # Required sections
88
- $RequiredSections = @(
89
- "## Specification:",
90
- "## Metadata",
91
- "## Functional Requirements",
92
- "## Acceptance Scenarios"
93
- )
94
-
95
- $Content = Get-Content $SpecFile -Raw -Encoding UTF8
96
- $MissingSections = @()
97
-
98
- foreach ($Section in $RequiredSections) {
99
- if ($Content -notmatch [regex]::Escape($Section)) {
100
- $MissingSections += $Section
101
- }
102
- }
103
-
104
- if ($MissingSections.Count -gt 0) {
105
- Write-Log "WARNING: Missing required sections: $($MissingSections -join ', ')"
106
- }
107
-
108
- # Check for clarifications needed
109
- $ClarificationMatches = [regex]::Matches($Content, 'NEEDS CLARIFICATION')
110
- if ($ClarificationMatches.Count -gt 0) {
111
- $ClarificationCount = $ClarificationMatches.Count
112
- Write-Log "WARNING: Specification has $ClarificationCount clarifications needed"
113
- return $ClarificationCount
114
- }
115
-
116
- return 0
117
- }
118
-
119
- # Main execution
120
- Write-Log "Processing specification..."
121
-
122
- # Get and sanitize feature directory
123
- $SanitizedDir = Get-CurrentFeatureDir -ProvidedDir $FeatureDir
124
-
125
- # Set file paths
126
- $SpecFile = Join-Path $ProjectRoot "specs" $SanitizedDir "spec.md"
127
- $TemplateFile = Join-Path $TemplatesDir "spec.md"
128
-
129
- # Ensure specs directory exists
130
- $SpecDir = Split-Path $SpecFile -Parent
131
- New-Item -ItemType Directory -Path $SpecDir -Force | Out-Null
132
-
133
- # Handle specification content
134
- if ($SpecContent) {
135
- Write-Log "Updating specification: $SpecFile"
136
- try {
137
- Set-Content -Path $SpecFile -Value $SpecContent -Encoding UTF8
138
- } catch {
139
- Exit-WithError "Failed to write specification content: $_"
140
- }
141
- } else {
142
- # Ensure specification exists from template
143
- if (-not (Test-Path $SpecFile)) {
144
- if (-not (Test-Path $TemplateFile)) {
145
- Exit-WithError "Template not found: $TemplateFile"
146
- }
147
-
148
- Write-Log "Creating specification from template: $SpecFile"
149
- try {
150
- Copy-Item $TemplateFile $SpecFile -Force
151
- } catch {
152
- Exit-WithError "Failed to copy specification template: $_"
153
- }
154
- } else {
155
- Write-Log "Specification already exists: $SpecFile"
156
- }
157
- }
158
-
159
- # Validate specification
160
- Write-Log "Validating specification..."
161
- $ClarificationCount = Validate-Specification -SpecFile $SpecFile
162
-
163
- # Check for missing sections
164
- $Content = Get-Content $SpecFile -Raw -Encoding UTF8
165
- $RequiredSections = @(
166
- "## Specification:",
167
- "## Metadata",
168
- "## Functional Requirements",
169
- "## Acceptance Scenarios"
170
- )
171
-
172
- $MissingSections = @()
173
- foreach ($Section in $RequiredSections) {
174
- if ($Content -notmatch [regex]::Escape($Section)) {
175
- $MissingSections += $Section
176
- }
177
- }
178
-
179
- Write-Log "Specification processing completed successfully"
180
-
181
- # Output results
182
- Write-Host "SPEC_FILE=$SpecFile"
183
- Write-Host "CLARIFICATIONS_NEEDED=$ClarificationCount"
184
- Write-Host "MISSING_SECTIONS=$($MissingSections.Count)"
185
- Write-Host "STATUS=updated"
@@ -1,263 +0,0 @@
1
- # SpecPulse Task Generation Script
2
- # Cross-platform PowerShell equivalent of pulse-task.sh
3
-
4
- param(
5
- [Parameter(Mandatory=$true)]
6
- [string]$FeatureDir,
7
-
8
- [string]$TaskContent = ""
9
- )
10
-
11
- $ErrorActionPreference = "Stop"
12
- $ProgressPreference = "SilentlyContinue"
13
-
14
- # Configuration
15
- $ScriptName = $MyInvocation.MyCommand.Name
16
- $ProjectRoot = $PSScriptRoot | Split-Path -Parent | Split-Path -Parent
17
- $MemoryDir = Join-Path $ProjectRoot "memory"
18
- $ContextFile = Join-Path $MemoryDir "context.md"
19
- $TemplatesDir = Join-Path $ProjectRoot "resources" "templates"
20
-
21
- function Write-Log {
22
- param([string]$Message)
23
- $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
24
- Write-Host "[$Timestamp] $ScriptName : $Message" -ForegroundColor Yellow
25
- }
26
-
27
- function Exit-WithError {
28
- param([string]$Message)
29
- Write-Log "ERROR: $Message"
30
- exit 1
31
- }
32
-
33
- function Sanitize-FeatureDir {
34
- param([string]$Dir)
35
-
36
- if ([string]::IsNullOrWhiteSpace($Dir)) {
37
- Exit-WithError "Feature directory cannot be empty"
38
- }
39
-
40
- # Remove non-alphanumeric characters except hyphens and underscores
41
- $Sanitized = $Dir -replace '[^a-zA-Z0-9_-]', ''
42
-
43
- if ([string]::IsNullOrWhiteSpace($Sanitized)) {
44
- Exit-WithError "Invalid feature directory: '$Dir'"
45
- }
46
-
47
- return $Sanitized
48
- }
49
-
50
- function Find-FeatureDirectory {
51
- if (-not (Test-Path $ContextFile)) {
52
- Exit-WithError "No context file found and no feature directory provided"
53
- }
54
-
55
- try {
56
- $Content = Get-Content $ContextFile -Raw -Encoding UTF8
57
- # Look for "Active Feature" section
58
- if ($Content -match 'Active Feature:\s*(.+)') {
59
- $FeatureDir = $matches[1].Trim()
60
- Write-Log "Using active feature from context: $FeatureDir"
61
- return $FeatureDir
62
- } else {
63
- Exit-WithError "No active feature found in context file"
64
- }
65
- } catch {
66
- Exit-WithError "Failed to read context file: $_"
67
- }
68
- }
69
-
70
- function Get-CurrentFeatureDir {
71
- param([string]$ProvidedDir)
72
-
73
- if ($ProvidedDir) {
74
- return Sanitize-FeatureDir -Dir $ProvidedDir
75
- } else {
76
- return Find-FeatureDirectory
77
- }
78
- }
79
-
80
- function Validate-TaskStructure {
81
- param([string]$TaskFile)
82
-
83
- if (-not (Test-Path $TaskFile)) {
84
- Exit-WithError "Task file does not exist: $TaskFile"
85
- }
86
-
87
- # Required sections
88
- $RequiredSections = @(
89
- "# Task List:",
90
- "## Progress Tracking",
91
- "### Parallel Group"
92
- )
93
-
94
- $Content = Get-Content $TaskFile -Raw -Encoding UTF8
95
- $MissingSections = @()
96
-
97
- foreach ($Section in $RequiredSections) {
98
- if ($Content -notmatch [regex]::Escape($Section)) {
99
- $MissingSections += $Section
100
- }
101
- }
102
-
103
- if ($MissingSections.Count -gt 0) {
104
- Write-Log "WARNING: Missing required sections: $($MissingSections -join ', ')"
105
- }
106
-
107
- return $MissingSections.Count
108
- }
109
-
110
- function Check-ConstitutionalGates {
111
- param([string]$TaskFile)
112
-
113
- if (-not (Test-Path $TaskFile)) {
114
- Exit-WithError "Task file does not exist: $TaskFile"
115
- }
116
-
117
- $Content = Get-Content $TaskFile -Raw -Encoding UTF8
118
- $GatesStatus = @{}
119
-
120
- # Check for constitutional gates compliance
121
- $Gates = @{
122
- "Simplicity Gate" = "Simplicity Gate"
123
- "Test-First Gate" = "Test-First Gate"
124
- "Integration-First Gate" = "Integration-First Gate"
125
- "Research Gate" = "Research Gate"
126
- }
127
-
128
- foreach ($Gate in $Gates.GetEnumerator()) {
129
- if ($Content -match $Gate.Value) {
130
- $GatesStatus[$Gate.Key] = "COMPLETED"
131
- } else {
132
- $GatesStatus[$Gate.Key] = "PENDING"
133
- }
134
- }
135
-
136
- return $GatesStatus
137
- }
138
-
139
- function Analyze-Tasks {
140
- param([string]$TaskFile)
141
-
142
- if (-not (Test-Path $TaskFile)) {
143
- Exit-WithError "Task file does not exist: $TaskFile"
144
- }
145
-
146
- $Content = Get-Content $TaskFile -Raw -Encoding UTF8
147
-
148
- # Count tasks
149
- $TaskMatches = [regex]::Matches($Content, '### T\d{3}:')
150
- $TaskCount = $TaskMatches.Count
151
-
152
- # Count parallel tasks
153
- $ParallelMatches = [regex]::Matches($Content, '\[P\]')
154
- $ParallelCount = $ParallelMatches.Count
155
-
156
- # Check for completion status
157
- $CompletionSection = $Content -match "## Progress Tracking"
158
- $CompletedTasks = 0
159
- $InProgressTasks = 0
160
- $BlockedTasks = 0
161
-
162
- if ($CompletionSection) {
163
- # Look for progress tracking YAML section
164
- if ($Content -match "completed:\s*(\d+)") {
165
- $CompletedTasks = [int]$matches[1]
166
- }
167
- if ($Content -match "in_progress:\s*(\d+)") {
168
- $InProgressTasks = [int]$matches[1]
169
- }
170
- if ($Content -match "blocked:\s*(\d+)") {
171
- $BlockedTasks = [int]$matches[1]
172
- }
173
- }
174
-
175
- return @{
176
- TotalTasks = $TaskCount
177
- ParallelTasks = $ParallelCount
178
- CompletedTasks = $CompletedTasks
179
- InProgressTasks = $InProgressTasks
180
- BlockedTasks = $BlockedTasks
181
- }
182
- }
183
-
184
- # Main execution
185
- Write-Log "Processing tasks..."
186
-
187
- # Get and sanitize feature directory
188
- $SanitizedDir = Get-CurrentFeatureDir -ProvidedDir $FeatureDir
189
-
190
- # Set file paths
191
- $TaskFile = Join-Path $ProjectRoot "tasks" $SanitizedDir "tasks.md"
192
- $PlanFile = Join-Path $ProjectRoot "plans" $SanitizedDir "plan.md"
193
- $TemplateFile = Join-Path $TemplatesDir "task.md"
194
-
195
- # Ensure tasks directory exists
196
- $TaskDir = Split-Path $TaskFile -Parent
197
- New-Item -ItemType Directory -Path $TaskDir -Force | Out-Null
198
-
199
- # Handle task content
200
- if ($TaskContent) {
201
- Write-Log "Updating task file: $TaskFile"
202
- try {
203
- Set-Content -Path $TaskFile -Value $TaskContent -Encoding UTF8
204
- } catch {
205
- Exit-WithError "Failed to write task content: $_"
206
- }
207
- } else {
208
- # Ensure task file exists from template
209
- if (-not (Test-Path $TaskFile)) {
210
- if (-not (Test-Path $TemplateFile)) {
211
- Exit-WithError "Template not found: $TemplateFile"
212
- }
213
-
214
- Write-Log "Creating task file from template: $TaskFile"
215
- try {
216
- Copy-Item $TemplateFile $TaskFile -Force
217
- } catch {
218
- Exit-WithError "Failed to copy task template: $_"
219
- }
220
- } else {
221
- Write-Log "Task file already exists: $TaskFile"
222
- }
223
- }
224
-
225
- # Validate task structure
226
- Write-Log "Validating task structure..."
227
- $MissingSections = Validate-TaskStructure -TaskFile $TaskFile
228
-
229
- # Check constitutional gates
230
- Write-Log "Checking constitutional gates..."
231
- $GatesStatus = Check-ConstitutionalGates -TaskFile $TaskFile
232
-
233
- # Analyze tasks
234
- Write-Log "Analyzing tasks..."
235
- $TaskAnalysis = Analyze-Tasks -TaskFile $TaskFile
236
-
237
- # Calculate completion percentage
238
- $CompletionPercentage = 0
239
- if ($TaskAnalysis.TotalTasks -gt 0) {
240
- $CompletionPercentage = [math]::Round(($TaskAnalysis.CompletedTasks / $TaskAnalysis.TotalTasks) * 100, 2)
241
- }
242
-
243
- # Count pending constitutional gates
244
- $PendingGates = 0
245
- foreach ($Status in $GatesStatus.Values) {
246
- if ($Status -eq "PENDING") {
247
- $PendingGates++
248
- }
249
- }
250
-
251
- Write-Log "Task processing completed successfully"
252
-
253
- # Output results
254
- Write-Host "TASK_FILE=$TaskFile"
255
- Write-Host "TOTAL_TASKS=$($TaskAnalysis.TotalTasks)"
256
- Write-Host "COMPLETED_TASKS=$($TaskAnalysis.CompletedTasks)"
257
- Write-Host "IN_PROGRESS_TASKS=$($TaskAnalysis.InProgressTasks)"
258
- Write-Host "BLOCKED_TASKS=$($TaskAnalysis.BlockedTasks)"
259
- Write-Host "PARALLEL_TASKS=$($TaskAnalysis.ParallelTasks)"
260
- Write-Host "COMPLETION_PERCENTAGE=$CompletionPercentage"
261
- Write-Host "MISSING_SECTIONS=$MissingSections"
262
- Write-Host "CONSTITUTIONAL_GATES_PENDING=$PendingGates"
263
- Write-Host "STATUS=processed"