specpulse 1.4.1__py3-none-any.whl → 1.4.2__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.
- specpulse/__init__.py +1 -1
- specpulse/cli/main.py +30 -8
- specpulse/core/specpulse.py +328 -3
- specpulse/core/validator.py +115 -5
- specpulse/resources/commands/gemini/sp-pulse.toml +80 -23
- specpulse/resources/commands/gemini/sp-spec.toml +90 -45
- specpulse/resources/scripts/sp-pulse-decompose.ps1 +74 -0
- specpulse/resources/scripts/sp-pulse-execute.ps1 +177 -0
- specpulse/resources/scripts/sp-pulse-init.ps1 +36 -11
- specpulse/resources/scripts/sp-pulse-init.sh +29 -8
- specpulse/resources/scripts/sp-pulse-plan.sh +42 -17
- specpulse/resources/scripts/sp-pulse-spec.sh +49 -25
- specpulse/resources/scripts/sp-pulse-task.sh +49 -17
- specpulse/resources/templates/decomposition/api-contract.yaml +344 -12
- specpulse/resources/templates/decomposition/integration-plan.md +249 -97
- specpulse/resources/templates/decomposition/interface.ts +244 -13
- specpulse/resources/templates/decomposition/microservice.md +151 -0
- specpulse/resources/templates/decomposition/service-plan.md +187 -155
- specpulse/resources/templates/plan.md +134 -225
- specpulse/resources/templates/spec.md +94 -125
- specpulse/resources/templates/task.md +216 -161
- specpulse/utils/console.py +54 -6
- specpulse/utils/git_utils.py +47 -4
- specpulse/utils/version_check.py +15 -2
- {specpulse-1.4.1.dist-info → specpulse-1.4.2.dist-info}/METADATA +33 -17
- {specpulse-1.4.1.dist-info → specpulse-1.4.2.dist-info}/RECORD +30 -28
- specpulse/resources/templates/decomposition/microservices.md +0 -35
- {specpulse-1.4.1.dist-info → specpulse-1.4.2.dist-info}/WHEEL +0 -0
- {specpulse-1.4.1.dist-info → specpulse-1.4.2.dist-info}/entry_points.txt +0 -0
- {specpulse-1.4.1.dist-info → specpulse-1.4.2.dist-info}/licenses/LICENSE +0 -0
- {specpulse-1.4.1.dist-info → specpulse-1.4.2.dist-info}/top_level.txt +0 -0
@@ -1,52 +1,97 @@
|
|
1
|
-
description = "Create or manage feature specifications
|
1
|
+
description = "Create or manage feature specifications using AI-optimized templates"
|
2
2
|
prompt = """
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
-
|
43
|
-
|
44
|
-
5.
|
45
|
-
|
46
|
-
|
3
|
+
## CRITICAL FILE EDIT RESTRICTIONS
|
4
|
+
**NEVER EDIT:** templates/, scripts/, commands/, .claude/, .gemini/
|
5
|
+
**ONLY EDIT:** specs/, plans/, tasks/, memory/
|
6
|
+
Templates are COPIED to specs/ folder, then edited there
|
7
|
+
|
8
|
+
## Command: /sp-spec {{args}}
|
9
|
+
|
10
|
+
Create, update, or validate feature specifications using SpecPulse methodology.
|
11
|
+
|
12
|
+
Actions: create, update, validate, clarify (defaults to create)
|
13
|
+
|
14
|
+
### Implementation Steps:
|
15
|
+
|
16
|
+
1. **Detect current feature context**:
|
17
|
+
- Read memory/context.md for current feature metadata
|
18
|
+
- Use git branch name if available (e.g., 001-user-authentication)
|
19
|
+
- Fall back to most recently created feature directory
|
20
|
+
- If no context found, ask user to specify feature or run /sp-pulse first
|
21
|
+
|
22
|
+
2. **Parse arguments** to determine action:
|
23
|
+
- If starts with 'create': Generate new specification
|
24
|
+
- If starts with 'update': Modify existing specification
|
25
|
+
- If starts with 'validate': Check specification completeness
|
26
|
+
- If starts with 'clarify': Address [NEEDS CLARIFICATION] markers
|
27
|
+
- Default to 'create' with full arguments as description
|
28
|
+
|
29
|
+
3. **Run specification script**:
|
30
|
+
- !{bash scripts/sp-pulse-spec.sh "{{args}}"}
|
31
|
+
|
32
|
+
4. **For 'create' action**:
|
33
|
+
- Read template from @{templates/spec.md}
|
34
|
+
- Parse description to identify:
|
35
|
+
* Functional requirements (Must/Should/Could/Won't have)
|
36
|
+
* User stories with testable acceptance criteria
|
37
|
+
* Non-functional requirements (performance, security, scalability)
|
38
|
+
* Technical constraints and dependencies
|
39
|
+
- Fill template with AI-generated content
|
40
|
+
- Mark unclear items with [NEEDS CLARIFICATION]
|
41
|
+
- Create numbered spec file (spec-001.md, spec-002.md, etc.)
|
42
|
+
- Save to specs/XXX-feature/spec-XXX.md
|
43
|
+
|
44
|
+
5. **Generate comprehensive specification**:
|
45
|
+
- Executive Summary
|
46
|
+
- Problem Statement
|
47
|
+
- Proposed Solution
|
48
|
+
- Functional Requirements (FR-001, FR-002, etc.)
|
49
|
+
- Non-Functional Requirements (performance, security, scalability)
|
50
|
+
- User Stories with acceptance criteria
|
51
|
+
- Technical Constraints
|
52
|
+
- Dependencies
|
53
|
+
- Risks and Mitigations
|
54
|
+
- Success Criteria
|
55
|
+
- Open Questions marked with [NEEDS CLARIFICATION]
|
56
|
+
|
57
|
+
6. **For 'update' action**:
|
58
|
+
- Show list of existing spec files
|
59
|
+
- Ask user which spec file to update
|
60
|
+
- Read selected specification
|
61
|
+
- Ask for clarifications or changes
|
62
|
+
- Update content while preserving structure
|
63
|
+
- Remove resolved [NEEDS CLARIFICATION] markers
|
64
|
+
|
65
|
+
7. **For 'validate' action**:
|
66
|
+
- Show list of existing spec files
|
67
|
+
- Run validation script
|
68
|
+
- Check all required sections are filled
|
69
|
+
- Count [NEEDS CLARIFICATION] markers
|
70
|
+
- Verify acceptance criteria are testable
|
71
|
+
- Report validation results
|
72
|
+
|
73
|
+
8. **Update context and validate**:
|
74
|
+
- Update memory/context.md with specification status
|
75
|
+
- Check SDD compliance (Principle 1: Specification First)
|
76
|
+
- Validate all sections are filled
|
77
|
+
- Report any missing or incomplete sections
|
78
|
+
|
79
|
+
### Example AI-Generated Content:
|
80
|
+
For "User authentication with OAuth2":
|
81
|
+
- FR-001: System SHALL support OAuth2 authentication with Google/GitHub
|
82
|
+
- FR-002: System SHALL issue JWT tokens valid for 24 hours
|
83
|
+
- NFR-001: Authentication response time < 200ms
|
84
|
+
- User Story: As a user, I want to login with Google so that I don't need to remember another password
|
85
|
+
|
86
|
+
### SDD Compliance Checklist:
|
87
|
+
- [ ] Every requirement is testable (Principle 1)
|
88
|
+
- [ ] User stories have clear acceptance criteria (Principle 1)
|
89
|
+
- [ ] Dependencies are identified (Principle 4)
|
90
|
+
- [ ] Success metrics defined (Principle 6)
|
47
91
|
|
48
92
|
Examples:
|
49
93
|
- /sp-spec user authentication with OAuth2 and email/password
|
50
94
|
- /sp-spec update
|
51
95
|
- /sp-spec validate
|
96
|
+
- /sp-spec clarify
|
52
97
|
"""
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# SpecPulse Decomposition Orchestrator - PowerShell Version
|
2
|
+
# Validates decomposition request and returns status for AI processing
|
3
|
+
|
4
|
+
param(
|
5
|
+
[Parameter(Mandatory=$false, Position=0)]
|
6
|
+
[string]$SpecId,
|
7
|
+
|
8
|
+
[Parameter(Mandatory=$false, Position=1)]
|
9
|
+
[string]$Action = "validate"
|
10
|
+
)
|
11
|
+
|
12
|
+
# Configuration
|
13
|
+
$ScriptDir = Split-Path -Parent $PSCommandPath
|
14
|
+
$ProjectRoot = Split-Path -Parent $ScriptDir
|
15
|
+
|
16
|
+
# Colors for output
|
17
|
+
$Green = "Green"
|
18
|
+
$Yellow = "Yellow"
|
19
|
+
|
20
|
+
Write-Host "[SpecPulse Decompose]" -ForegroundColor $Green -NoNewline
|
21
|
+
Write-Host " Processing spec: $($SpecId ?? 'current')"
|
22
|
+
|
23
|
+
# Find specification
|
24
|
+
if ([string]::IsNullOrEmpty($SpecId)) {
|
25
|
+
$specDirs = Get-ChildItem -Path "$ProjectRoot\specs" -Directory -ErrorAction SilentlyContinue |
|
26
|
+
Sort-Object Name -Descending |
|
27
|
+
Select-Object -First 1
|
28
|
+
$SpecDir = if ($specDirs) { $specDirs.FullName } else { $null }
|
29
|
+
} else {
|
30
|
+
$specDirs = Get-ChildItem -Path "$ProjectRoot\specs" -Directory -Filter "${SpecId}*" -ErrorAction SilentlyContinue |
|
31
|
+
Select-Object -First 1
|
32
|
+
$SpecDir = if ($specDirs) { $specDirs.FullName } else { $null }
|
33
|
+
}
|
34
|
+
|
35
|
+
if (-not $SpecDir -or -not (Test-Path $SpecDir)) {
|
36
|
+
Write-Host "ERROR: No specification found" -ForegroundColor Red
|
37
|
+
Write-Host "SUGGESTION: Run /sp-spec create first"
|
38
|
+
exit 1
|
39
|
+
}
|
40
|
+
|
41
|
+
# Check complexity (simple heuristic)
|
42
|
+
$specFiles = Get-ChildItem -Path $SpecDir -Filter "spec-*.md" -ErrorAction SilentlyContinue |
|
43
|
+
Sort-Object Name |
|
44
|
+
Select-Object -Last 1
|
45
|
+
|
46
|
+
if ($specFiles) {
|
47
|
+
$SpecFile = $specFiles.FullName
|
48
|
+
$LineCount = (Get-Content $SpecFile | Measure-Object -Line).Lines
|
49
|
+
|
50
|
+
Write-Output "SPEC_FILE=$SpecFile"
|
51
|
+
Write-Output "COMPLEXITY=$LineCount lines"
|
52
|
+
|
53
|
+
if ($LineCount -gt 100) {
|
54
|
+
Write-Output "RECOMMENDATION=Decomposition advised (complex spec)"
|
55
|
+
} else {
|
56
|
+
Write-Output "RECOMMENDATION=Single service may suffice"
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
# Check for existing decomposition
|
61
|
+
$DecompositionPath = Join-Path $SpecDir "decomposition"
|
62
|
+
if (Test-Path $DecompositionPath) {
|
63
|
+
Write-Output "STATUS=Decomposition exists"
|
64
|
+
Write-Output "PATH=$DecompositionPath"
|
65
|
+
} else {
|
66
|
+
Write-Output "STATUS=Ready for decomposition"
|
67
|
+
Write-Output "PATH=$SpecDir"
|
68
|
+
}
|
69
|
+
|
70
|
+
# Return template paths for AI
|
71
|
+
Write-Output "TEMPLATES_DIR=templates/decomposition"
|
72
|
+
Write-Output "MEMORY_FILE=memory/context.md"
|
73
|
+
|
74
|
+
exit 0
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# Execute tasks continuously from task list - PowerShell Version
|
2
|
+
|
3
|
+
param(
|
4
|
+
[Parameter(Mandatory=$false, Position=0)]
|
5
|
+
[string]$Command = "next",
|
6
|
+
|
7
|
+
[Parameter(Mandatory=$false, Position=1)]
|
8
|
+
[string]$FeatureDir
|
9
|
+
)
|
10
|
+
|
11
|
+
# Configuration
|
12
|
+
$ScriptName = Split-Path -Leaf $PSCommandPath
|
13
|
+
$ScriptDir = Split-Path -Parent $PSCommandPath
|
14
|
+
$ProjectRoot = Split-Path -Parent $ScriptDir
|
15
|
+
|
16
|
+
# Logging function
|
17
|
+
function Log-Message {
|
18
|
+
param([string]$Message)
|
19
|
+
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
20
|
+
Write-Host "[$timestamp] ${ScriptName}: $Message" -ForegroundColor Cyan
|
21
|
+
}
|
22
|
+
|
23
|
+
# Error handling function
|
24
|
+
function Exit-WithError {
|
25
|
+
param([string]$Message)
|
26
|
+
Write-Host "ERROR: $Message" -ForegroundColor Red
|
27
|
+
exit 1
|
28
|
+
}
|
29
|
+
|
30
|
+
# Find active feature if not provided
|
31
|
+
if ([string]::IsNullOrEmpty($FeatureDir)) {
|
32
|
+
$ContextFile = Join-Path $ProjectRoot "memory\context.md"
|
33
|
+
if (Test-Path $ContextFile) {
|
34
|
+
# Extract active feature from context
|
35
|
+
$contextContent = Get-Content $ContextFile -Raw
|
36
|
+
if ($contextContent -match "Active Feature:\s*(.+)") {
|
37
|
+
$FeatureName = $matches[1].Trim()
|
38
|
+
}
|
39
|
+
if ($contextContent -match "Feature ID:\s*(.+)") {
|
40
|
+
$FeatureId = $matches[1].Trim()
|
41
|
+
}
|
42
|
+
|
43
|
+
if ($FeatureId -and $FeatureName) {
|
44
|
+
# Convert to branch name format
|
45
|
+
$BranchSafeName = $FeatureName.ToLower() -replace '[^a-z0-9-]', '-' -replace '--+', '-' -replace '^-|-$', ''
|
46
|
+
$FeatureDir = "$FeatureId-$BranchSafeName"
|
47
|
+
Log-Message "Using active feature: $FeatureDir"
|
48
|
+
} else {
|
49
|
+
Exit-WithError "No active feature found in context file"
|
50
|
+
}
|
51
|
+
} else {
|
52
|
+
Exit-WithError "No feature directory provided and no context file found"
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
$TaskDir = Join-Path $ProjectRoot "tasks\$FeatureDir"
|
57
|
+
|
58
|
+
# Ensure tasks directory exists
|
59
|
+
if (-not (Test-Path $TaskDir)) {
|
60
|
+
Exit-WithError "Tasks directory not found: $TaskDir"
|
61
|
+
}
|
62
|
+
|
63
|
+
# Find latest task file
|
64
|
+
$taskFiles = Get-ChildItem -Path $TaskDir -Filter "*.md" -ErrorAction SilentlyContinue |
|
65
|
+
Sort-Object LastWriteTime -Descending |
|
66
|
+
Select-Object -First 1
|
67
|
+
|
68
|
+
if (-not $taskFiles) {
|
69
|
+
Exit-WithError "No task files found in $TaskDir"
|
70
|
+
}
|
71
|
+
|
72
|
+
$TaskFile = $taskFiles.FullName
|
73
|
+
Log-Message "Analyzing task file: $TaskFile"
|
74
|
+
|
75
|
+
# Read task content
|
76
|
+
$taskContent = Get-Content $TaskFile -Raw
|
77
|
+
|
78
|
+
# Detect if decomposed (service-specific tasks)
|
79
|
+
$IsDecomposed = $false
|
80
|
+
if ($taskContent -match "AUTH-T[0-9]|USER-T[0-9]|INT-T[0-9]") {
|
81
|
+
$IsDecomposed = $true
|
82
|
+
Log-Message "Detected decomposed architecture with service-specific tasks"
|
83
|
+
}
|
84
|
+
|
85
|
+
# Count task status using regex
|
86
|
+
$taskPattern = '^- \[.\] (T[0-9]{3}|[A-Z]+-T[0-9]{3})'
|
87
|
+
$allTasks = [regex]::Matches($taskContent, $taskPattern, [System.Text.RegularExpressions.RegexOptions]::Multiline)
|
88
|
+
$TotalTasks = $allTasks.Count
|
89
|
+
|
90
|
+
$CompletedTasks = ([regex]::Matches($taskContent, '^- \[x\] (T[0-9]{3}|[A-Z]+-T[0-9]{3})', [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
91
|
+
$PendingTasks = ([regex]::Matches($taskContent, '^- \[ \] (T[0-9]{3}|[A-Z]+-T[0-9]{3})', [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
92
|
+
$InProgressTasks = ([regex]::Matches($taskContent, '^- \[>\] (T[0-9]{3}|[A-Z]+-T[0-9]{3})', [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
93
|
+
$BlockedTasks = ([regex]::Matches($taskContent, '^- \[!\] (T[0-9]{3}|[A-Z]+-T[0-9]{3})', [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
94
|
+
|
95
|
+
# Find next task to execute
|
96
|
+
$NextTask = ""
|
97
|
+
$TaskDetails = ""
|
98
|
+
|
99
|
+
switch ($Command) {
|
100
|
+
{ $_ -in "next", "continue" } {
|
101
|
+
# Find first in-progress task
|
102
|
+
$inProgressMatch = [regex]::Match($taskContent, '^- \[>\] ((T[0-9]{3}|[A-Z]+-T[0-9]{3}): .+)$', [System.Text.RegularExpressions.RegexOptions]::Multiline)
|
103
|
+
if ($inProgressMatch.Success) {
|
104
|
+
$NextTask = $inProgressMatch.Groups[1].Value
|
105
|
+
$TaskDetails = "RESUMING IN-PROGRESS TASK"
|
106
|
+
} else {
|
107
|
+
# Find first pending task
|
108
|
+
$pendingMatch = [regex]::Match($taskContent, '^- \[ \] ((T[0-9]{3}|[A-Z]+-T[0-9]{3}): .+)$', [System.Text.RegularExpressions.RegexOptions]::Multiline)
|
109
|
+
if ($pendingMatch.Success) {
|
110
|
+
$NextTask = $pendingMatch.Groups[1].Value
|
111
|
+
$TaskDetails = "STARTING NEW TASK"
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|
115
|
+
"all" {
|
116
|
+
if ($PendingTasks -gt 0 -or $InProgressTasks -gt 0) {
|
117
|
+
$NextTask = "ALL_REMAINING"
|
118
|
+
$TaskDetails = "EXECUTE ALL TASKS WITHOUT STOPPING"
|
119
|
+
}
|
120
|
+
}
|
121
|
+
default {
|
122
|
+
# Specific task requested
|
123
|
+
$specificMatch = [regex]::Match($taskContent, "^- \[.\] (($Command): .+)$", [System.Text.RegularExpressions.RegexOptions]::Multiline)
|
124
|
+
if ($specificMatch.Success) {
|
125
|
+
$NextTask = $specificMatch.Groups[1].Value
|
126
|
+
$TaskDetails = "EXECUTE SPECIFIC TASK"
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
# Calculate progress
|
132
|
+
if ($TotalTasks -gt 0) {
|
133
|
+
$Progress = [math]::Round(($CompletedTasks / $TotalTasks) * 100)
|
134
|
+
} else {
|
135
|
+
$Progress = 0
|
136
|
+
}
|
137
|
+
|
138
|
+
# Output status
|
139
|
+
Write-Output "TASK_FILE=$TaskFile"
|
140
|
+
Write-Output "TOTAL_TASKS=$TotalTasks"
|
141
|
+
Write-Output "COMPLETED_TASKS=$CompletedTasks"
|
142
|
+
Write-Output "PENDING_TASKS=$PendingTasks"
|
143
|
+
Write-Output "IN_PROGRESS_TASKS=$InProgressTasks"
|
144
|
+
Write-Output "BLOCKED_TASKS=$BlockedTasks"
|
145
|
+
Write-Output "PROGRESS=$Progress%"
|
146
|
+
|
147
|
+
if ($IsDecomposed) {
|
148
|
+
Write-Output "ARCHITECTURE=Microservices"
|
149
|
+
} else {
|
150
|
+
Write-Output "ARCHITECTURE=Monolithic"
|
151
|
+
}
|
152
|
+
|
153
|
+
if ($NextTask) {
|
154
|
+
Write-Output "NEXT_TASK=$NextTask"
|
155
|
+
Write-Output "ACTION=$TaskDetails"
|
156
|
+
if ($Command -eq "all") {
|
157
|
+
Write-Output "MODE=CONTINUOUS"
|
158
|
+
Write-Output "INSTRUCTION=Execute all tasks without stopping, no explanations between tasks"
|
159
|
+
} else {
|
160
|
+
Write-Output "MODE=SINGLE"
|
161
|
+
Write-Output "INSTRUCTION=Execute this task and report results"
|
162
|
+
}
|
163
|
+
} else {
|
164
|
+
if ($CompletedTasks -eq $TotalTasks -and $TotalTasks -gt 0) {
|
165
|
+
Write-Output "STATUS=ALL_COMPLETE"
|
166
|
+
Write-Output "MESSAGE=Congratulations! All tasks have been completed!"
|
167
|
+
} elseif ($BlockedTasks -gt 0) {
|
168
|
+
Write-Output "STATUS=BLOCKED"
|
169
|
+
Write-Output "MESSAGE=All remaining tasks are blocked. Resolve blockers first."
|
170
|
+
} else {
|
171
|
+
Write-Output "STATUS=NO_TASKS"
|
172
|
+
Write-Output "MESSAGE=No tasks available to execute"
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
Log-Message "Task analysis complete"
|
177
|
+
exit 0
|
@@ -61,23 +61,48 @@ try {
|
|
61
61
|
Exit-WithError "Failed to create directories: $_"
|
62
62
|
}
|
63
63
|
|
64
|
-
#
|
64
|
+
# Validate templates exist but don't copy them directly
|
65
65
|
$TemplateDir = Join-Path $ProjectRoot "templates"
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
$
|
70
|
-
|
71
|
-
|
72
|
-
|
67
|
+
# Validate all required templates exist
|
68
|
+
@("spec.md", "plan.md", "task.md") | ForEach-Object {
|
69
|
+
$templatePath = Join-Path $TemplateDir $_
|
70
|
+
if (-not (Test-Path $templatePath)) {
|
71
|
+
Exit-WithError "Template not found: $templatePath. Please run 'specpulse init' to initialize templates."
|
72
|
+
}
|
73
73
|
}
|
74
74
|
|
75
|
+
# Create marker files that indicate AI should use templates to generate content
|
76
|
+
# These are placeholder files that will be replaced by AI-generated content
|
75
77
|
try {
|
76
|
-
|
77
|
-
|
78
|
-
|
78
|
+
$specContent = @"
|
79
|
+
# Specification for $FeatureName
|
80
|
+
|
81
|
+
<!-- TO BE GENERATED FROM TEMPLATE: $TemplateDir\spec.md -->
|
82
|
+
<!-- FEATURE: $FeatureName -->
|
83
|
+
<!-- ID: $FeatureId -->
|
84
|
+
"@
|
85
|
+
Set-Content -Path "$SpecsDir\spec-001.md" -Value $specContent
|
86
|
+
|
87
|
+
$planContent = @"
|
88
|
+
# Implementation Plan for $FeatureName
|
89
|
+
|
90
|
+
<!-- TO BE GENERATED FROM TEMPLATE: $TemplateDir\plan.md -->
|
91
|
+
<!-- FEATURE: $FeatureName -->
|
92
|
+
<!-- ID: $FeatureId -->
|
93
|
+
"@
|
94
|
+
Set-Content -Path "$PlansDir\plan-001.md" -Value $planContent
|
95
|
+
|
96
|
+
$taskContent = @"
|
97
|
+
# Task Breakdown for $FeatureName
|
98
|
+
|
99
|
+
<!-- TO BE GENERATED FROM TEMPLATE: $TemplateDir\task.md -->
|
100
|
+
<!-- FEATURE: $FeatureName -->
|
101
|
+
<!-- ID: $FeatureId -->
|
102
|
+
"@
|
103
|
+
Set-Content -Path "$TasksDir\task-001.md" -Value $taskContent
|
79
104
|
} catch {
|
80
|
-
Exit-WithError "Failed to
|
105
|
+
Exit-WithError "Failed to create marker files: $_"
|
81
106
|
}
|
82
107
|
|
83
108
|
# Update context
|
@@ -55,16 +55,37 @@ mkdir -p "$SPECS_DIR" || error_exit "Failed to create specs directory: $SPECS_DI
|
|
55
55
|
mkdir -p "$PLANS_DIR" || error_exit "Failed to create plans directory: $PLANS_DIR"
|
56
56
|
mkdir -p "$TASKS_DIR" || error_exit "Failed to create tasks directory: $TASKS_DIR"
|
57
57
|
|
58
|
-
#
|
58
|
+
# Validate templates exist but don't copy them directly
|
59
59
|
TEMPLATE_DIR="$PROJECT_ROOT/templates"
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
61
|
+
# Validate all required templates exist
|
62
|
+
for template in spec.md plan.md task.md; do
|
63
|
+
if [ ! -f "$TEMPLATE_DIR/$template" ]; then
|
64
|
+
error_exit "Template not found: $TEMPLATE_DIR/$template. Please run 'specpulse init' to initialize templates."
|
65
|
+
fi
|
66
|
+
done
|
67
|
+
|
68
|
+
# Create marker files that indicate AI should use templates to generate content
|
69
|
+
# These are placeholder files that will be replaced by AI-generated content
|
70
|
+
echo "# Specification for $FEATURE_NAME" > "$SPECS_DIR/spec-001.md"
|
71
|
+
echo "# Implementation Plan for $FEATURE_NAME" > "$PLANS_DIR/plan-001.md"
|
72
|
+
echo "# Task Breakdown for $FEATURE_NAME" > "$TASKS_DIR/task-001.md"
|
73
|
+
|
74
|
+
# Add markers indicating these files need AI processing
|
75
|
+
echo "" >> "$SPECS_DIR/spec-001.md"
|
76
|
+
echo "<!-- TO BE GENERATED FROM TEMPLATE: $TEMPLATE_DIR/spec.md -->" >> "$SPECS_DIR/spec-001.md"
|
77
|
+
echo "<!-- FEATURE: $FEATURE_NAME -->" >> "$SPECS_DIR/spec-001.md"
|
78
|
+
echo "<!-- ID: $FEATURE_ID -->" >> "$SPECS_DIR/spec-001.md"
|
79
|
+
|
80
|
+
echo "" >> "$PLANS_DIR/plan-001.md"
|
81
|
+
echo "<!-- TO BE GENERATED FROM TEMPLATE: $TEMPLATE_DIR/plan.md -->" >> "$PLANS_DIR/plan-001.md"
|
82
|
+
echo "<!-- FEATURE: $FEATURE_NAME -->" >> "$PLANS_DIR/plan-001.md"
|
83
|
+
echo "<!-- ID: $FEATURE_ID -->" >> "$PLANS_DIR/plan-001.md"
|
84
|
+
|
85
|
+
echo "" >> "$TASKS_DIR/task-001.md"
|
86
|
+
echo "<!-- TO BE GENERATED FROM TEMPLATE: $TEMPLATE_DIR/task.md -->" >> "$TASKS_DIR/task-001.md"
|
87
|
+
echo "<!-- FEATURE: $FEATURE_NAME -->" >> "$TASKS_DIR/task-001.md"
|
88
|
+
echo "<!-- ID: $FEATURE_ID -->" >> "$TASKS_DIR/task-001.md"
|
68
89
|
|
69
90
|
# Update context
|
70
91
|
CONTEXT_FILE="$PROJECT_ROOT/memory/context.md"
|
@@ -41,8 +41,13 @@ PLAN_DIR="$PROJECT_ROOT/plans/${FEATURE_DIR}"
|
|
41
41
|
SPEC_DIR="$PROJECT_ROOT/specs/${FEATURE_DIR}"
|
42
42
|
TEMPLATE_FILE="$PROJECT_ROOT/templates/plan.md"
|
43
43
|
|
44
|
+
# Validate template file exists before proceeding
|
45
|
+
if [ ! -f "$TEMPLATE_FILE" ]; then
|
46
|
+
error_exit "Template not found: $TEMPLATE_FILE. Please ensure templates are properly initialized."
|
47
|
+
fi
|
48
|
+
|
44
49
|
# Ensure plans directory exists
|
45
|
-
mkdir -p "$PLAN_DIR"
|
50
|
+
mkdir -p "$PLAN_DIR" || error_exit "Failed to create plans directory: $PLAN_DIR"
|
46
51
|
|
47
52
|
# Find latest spec file
|
48
53
|
if [ -d "$SPEC_DIR" ]; then
|
@@ -56,8 +61,13 @@ fi
|
|
56
61
|
|
57
62
|
# Find next available plan number or create new one
|
58
63
|
if [ -d "$PLAN_DIR" ]; then
|
59
|
-
|
60
|
-
|
64
|
+
# Get the highest plan number and increment it
|
65
|
+
highest_plan=$(find "$PLAN_DIR" -name "plan-*.md" -exec basename {} .md \; | sed 's/plan-//' | sort -n | tail -1)
|
66
|
+
if [ -n "$highest_plan" ]; then
|
67
|
+
plan_number=$((highest_plan + 1))
|
68
|
+
else
|
69
|
+
plan_number=1
|
70
|
+
fi
|
61
71
|
else
|
62
72
|
plan_number=1
|
63
73
|
fi
|
@@ -68,25 +78,40 @@ if [ ! -f "$TEMPLATE_FILE" ]; then
|
|
68
78
|
error_exit "Template not found: $TEMPLATE_FILE"
|
69
79
|
fi
|
70
80
|
|
71
|
-
# Create plan
|
72
|
-
log "Creating implementation plan
|
73
|
-
|
81
|
+
# Create plan marker for AI generation
|
82
|
+
log "Creating implementation plan marker: $PLAN_FILE"
|
83
|
+
echo "# Implementation Plan - $FEATURE_DIR" > "$PLAN_FILE"
|
84
|
+
echo "" >> "$PLAN_FILE"
|
85
|
+
echo "<!-- AI: Please generate plan using template: $TEMPLATE_FILE -->" >> "$PLAN_FILE"
|
86
|
+
echo "<!-- SPEC_FILE: $SPEC_FILE -->" >> "$PLAN_FILE"
|
87
|
+
echo "<!-- FEATURE_DIR: $FEATURE_DIR -->" >> "$PLAN_FILE"
|
88
|
+
echo "<!-- FEATURE_ID: $FEATURE_ID -->" >> "$PLAN_FILE"
|
89
|
+
echo "" >> "$PLAN_FILE"
|
90
|
+
echo "## Awaiting AI Generation" >> "$PLAN_FILE"
|
91
|
+
echo "This plan needs to be generated from the template based on specification: $SPEC_FILE" >> "$PLAN_FILE"
|
74
92
|
|
75
93
|
# Validate plan structure
|
76
94
|
log "Validating implementation plan..."
|
77
95
|
|
78
|
-
# Check
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
96
|
+
# Check if file needs AI generation
|
97
|
+
if grep -q "Awaiting AI Generation" "$PLAN_FILE"; then
|
98
|
+
log "WARNING: Plan needs to be generated by AI from template"
|
99
|
+
MISSING_SECTIONS=("ALL - Awaiting AI Generation")
|
100
|
+
GATE_STATUS="PENDING"
|
101
|
+
else
|
102
|
+
# Check for required sections only if file has been generated
|
103
|
+
REQUIRED_SECTIONS=("## Implementation Plan:" "## Specification Reference" "## Phase -1: Pre-Implementation Gates" "## Implementation Phases")
|
104
|
+
MISSING_SECTIONS=()
|
105
|
+
|
106
|
+
for section in "${REQUIRED_SECTIONS[@]}"; do
|
107
|
+
if ! grep -q "$section" "$PLAN_FILE"; then
|
108
|
+
MISSING_SECTIONS+=("$section")
|
109
|
+
fi
|
110
|
+
done
|
111
|
+
|
112
|
+
if [ ${#MISSING_SECTIONS[@]} -gt 0 ]; then
|
113
|
+
log "WARNING: Missing required sections: ${MISSING_SECTIONS[*]}"
|
85
114
|
fi
|
86
|
-
done
|
87
|
-
|
88
|
-
if [ ${#MISSING_SECTIONS[@]} -gt 0 ]; then
|
89
|
-
log "WARNING: Missing required sections: ${MISSING_SECTIONS[*]}"
|
90
115
|
fi
|
91
116
|
|
92
117
|
# Check SDD Gates
|