specpulse 1.4.3__py3-none-any.whl → 1.4.4__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/resources/scripts/sp-pulse-execute.ps1 +58 -23
- specpulse/resources/scripts/sp-pulse-execute.sh +9 -9
- specpulse/resources/scripts/sp-pulse-init.ps1 +12 -9
- specpulse/resources/scripts/sp-pulse-init.sh +12 -9
- specpulse/resources/scripts/sp-pulse-plan.ps1 +48 -23
- specpulse/resources/scripts/sp-pulse-plan.sh +1 -1
- specpulse/resources/scripts/sp-pulse-spec.ps1 +45 -20
- specpulse/resources/scripts/sp-pulse-spec.sh +1 -1
- specpulse/resources/scripts/sp-pulse-task.ps1 +61 -31
- specpulse/resources/scripts/sp-pulse-task.sh +1 -1
- {specpulse-1.4.3.dist-info → specpulse-1.4.4.dist-info}/METADATA +8 -2
- {specpulse-1.4.3.dist-info → specpulse-1.4.4.dist-info}/RECORD +16 -16
- {specpulse-1.4.3.dist-info → specpulse-1.4.4.dist-info}/WHEEL +0 -0
- {specpulse-1.4.3.dist-info → specpulse-1.4.4.dist-info}/entry_points.txt +0 -0
- {specpulse-1.4.3.dist-info → specpulse-1.4.4.dist-info}/licenses/LICENSE +0 -0
- {specpulse-1.4.3.dist-info → specpulse-1.4.4.dist-info}/top_level.txt +0 -0
@@ -82,15 +82,34 @@ if ($taskContent -match "AUTH-T[0-9]|USER-T[0-9]|INT-T[0-9]") {
|
|
82
82
|
Log-Message "Detected decomposed architecture with service-specific tasks"
|
83
83
|
}
|
84
84
|
|
85
|
-
# Count task status using
|
86
|
-
|
87
|
-
|
88
|
-
$TotalTasks = $
|
89
|
-
|
90
|
-
|
91
|
-
$
|
92
|
-
$
|
93
|
-
$
|
85
|
+
# Count task status using the actual format used in task files
|
86
|
+
# Format is: ### T001: Task Name
|
87
|
+
# **Status**: [x] Completed
|
88
|
+
$TotalTasks = ([regex]::Matches($taskContent, '^### T[0-9]{3}:', [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
89
|
+
|
90
|
+
# Count completed tasks by finding task headers followed by status within next few lines
|
91
|
+
$CompletedTasks = 0
|
92
|
+
$PendingTasks = 0
|
93
|
+
$InProgressTasks = 0
|
94
|
+
$BlockedTasks = 0
|
95
|
+
|
96
|
+
$taskHeaders = [regex]::Matches($taskContent, '^### (T[0-9]{3}):', [System.Text.RegularExpressions.RegexOptions]::Multiline)
|
97
|
+
foreach ($header in $taskHeaders) {
|
98
|
+
$taskId = $header.Groups[1].Value
|
99
|
+
$startIndex = $header.Index
|
100
|
+
$endIndex = if ($header.Index + 500 -lt $taskContent.Length) { $header.Index + 500 } else { $taskContent.Length }
|
101
|
+
$taskSection = $taskContent.Substring($startIndex, $endIndex - $startIndex)
|
102
|
+
|
103
|
+
if ($taskSection -match '\*\*Status\*\*:\s*\[x\]') {
|
104
|
+
$CompletedTasks++
|
105
|
+
} elseif ($taskSection -match '\*\*Status\*\*:\s*\[ \]') {
|
106
|
+
$PendingTasks++
|
107
|
+
} elseif ($taskSection -match '\*\*Status\*\*:\s*\[>\]') {
|
108
|
+
$InProgressTasks++
|
109
|
+
} elseif ($taskSection -match '\*\*Status\*\*:\s*\[!\]') {
|
110
|
+
$BlockedTasks++
|
111
|
+
}
|
112
|
+
}
|
94
113
|
|
95
114
|
# Find next task to execute
|
96
115
|
$NextTask = ""
|
@@ -98,17 +117,34 @@ $TaskDetails = ""
|
|
98
117
|
|
99
118
|
switch ($Command) {
|
100
119
|
{ $_ -in "next", "continue" } {
|
101
|
-
# Find first in-progress task
|
102
|
-
|
103
|
-
|
104
|
-
$
|
105
|
-
$
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
if ($
|
110
|
-
$NextTask = $
|
111
|
-
$TaskDetails = "
|
120
|
+
# Find first in-progress or pending task
|
121
|
+
foreach ($header in $taskHeaders) {
|
122
|
+
$taskId = $header.Groups[1].Value
|
123
|
+
$startIndex = $header.Index
|
124
|
+
$endIndex = if ($header.Index + 500 -lt $taskContent.Length) { $header.Index + 500 } else { $taskContent.Length }
|
125
|
+
$taskSection = $taskContent.Substring($startIndex, $endIndex - $startIndex)
|
126
|
+
|
127
|
+
# Check for in-progress task first
|
128
|
+
if ($taskSection -match '\*\*Status\*\*:\s*\[>\]') {
|
129
|
+
$NextTask = $taskId
|
130
|
+
$TaskDetails = "RESUMING IN-PROGRESS TASK"
|
131
|
+
break
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
# If no in-progress task found, find first pending
|
136
|
+
if (-not $NextTask) {
|
137
|
+
foreach ($header in $taskHeaders) {
|
138
|
+
$taskId = $header.Groups[1].Value
|
139
|
+
$startIndex = $header.Index
|
140
|
+
$endIndex = if ($header.Index + 500 -lt $taskContent.Length) { $header.Index + 500 } else { $taskContent.Length }
|
141
|
+
$taskSection = $taskContent.Substring($startIndex, $endIndex - $startIndex)
|
142
|
+
|
143
|
+
if ($taskSection -match '\*\*Status\*\*:\s*\[ \]') {
|
144
|
+
$NextTask = $taskId
|
145
|
+
$TaskDetails = "STARTING NEW TASK"
|
146
|
+
break
|
147
|
+
}
|
112
148
|
}
|
113
149
|
}
|
114
150
|
}
|
@@ -120,9 +156,8 @@ switch ($Command) {
|
|
120
156
|
}
|
121
157
|
default {
|
122
158
|
# Specific task requested
|
123
|
-
|
124
|
-
|
125
|
-
$NextTask = $specificMatch.Groups[1].Value
|
159
|
+
if ($taskContent -match "^### ($Command):" ) {
|
160
|
+
$NextTask = $Command
|
126
161
|
$TaskDetails = "EXECUTE SPECIFIC TASK"
|
127
162
|
}
|
128
163
|
}
|
@@ -67,23 +67,23 @@ if grep -qE "AUTH-T[0-9]|USER-T[0-9]|INT-T[0-9]" "$TASK_FILE" 2>/dev/null; then
|
|
67
67
|
log "Detected decomposed architecture with service-specific tasks"
|
68
68
|
fi
|
69
69
|
|
70
|
-
# Count task status
|
71
|
-
TOTAL_TASKS=$(grep -cE "
|
72
|
-
COMPLETED_TASKS=$(
|
73
|
-
PENDING_TASKS=$(
|
74
|
-
IN_PROGRESS_TASKS=$(
|
75
|
-
BLOCKED_TASKS=$(
|
70
|
+
# Count task status - handle the actual format used in task files
|
71
|
+
TOTAL_TASKS=$(grep -cE "^### T[0-9]{3}:" "$TASK_FILE" 2>/dev/null || echo "0")
|
72
|
+
COMPLETED_TASKS=$(awk '/^### T[0-9]{3}:/{task=$0; found=0; for(i=0; i<5; i++) {getline; if(/^\*\*Status\*\*: \[x\]/) {found=1; break} if(/^###/) break} if(found) count++} END{print count+0}' "$TASK_FILE" 2>/dev/null || echo "0")
|
73
|
+
PENDING_TASKS=$(awk '/^### T[0-9]{3}:/{task=$0; found=0; for(i=0; i<5; i++) {getline; if(/^\*\*Status\*\*: \[ \]/) {found=1; break} if(/^###/) break} if(found) count++} END{print count+0}' "$TASK_FILE" 2>/dev/null || echo "0")
|
74
|
+
IN_PROGRESS_TASKS=$(awk '/^### T[0-9]{3}:/{task=$0; found=0; for(i=0; i<5; i++) {getline; if(/^\*\*Status\*\*: \[>\]/) {found=1; break} if(/^###/) break} if(found) count++} END{print count+0}' "$TASK_FILE" 2>/dev/null || echo "0")
|
75
|
+
BLOCKED_TASKS=$(awk '/^### T[0-9]{3}:/{task=$0; found=0; for(i=0; i<5; i++) {getline; if(/^\*\*Status\*\*: \[!\]/) {found=1; break} if(/^###/) break} if(found) count++} END{print count+0}' "$TASK_FILE" 2>/dev/null || echo "0")
|
76
76
|
|
77
77
|
# Find next task to execute
|
78
78
|
case "$COMMAND" in
|
79
79
|
"next"|"continue")
|
80
80
|
# Find first in-progress task
|
81
81
|
if [ "$IN_PROGRESS_TASKS" -gt 0 ]; then
|
82
|
-
NEXT_TASK=$(grep
|
82
|
+
NEXT_TASK=$(grep "^\*\*Status\*\*: \[>\]" "$TASK_FILE" -B1 | grep -E "^### T[0-9]{3}:" | head -1 | sed -E 's/^### (T[0-9]{3}):.*/\1/')
|
83
83
|
log "Resuming in-progress task: $NEXT_TASK"
|
84
84
|
# Otherwise find first pending task
|
85
85
|
elif [ "$PENDING_TASKS" -gt 0 ]; then
|
86
|
-
NEXT_TASK=$(grep
|
86
|
+
NEXT_TASK=$(grep "^\*\*Status\*\*: \[ \]" "$TASK_FILE" -B1 | grep -E "^### T[0-9]{3}:" | head -1 | sed -E 's/^### (T[0-9]{3}):.*/\1/')
|
87
87
|
log "Starting next pending task: $NEXT_TASK"
|
88
88
|
else
|
89
89
|
if [ "$BLOCKED_TASKS" -gt 0 ]; then
|
@@ -147,7 +147,7 @@ fi
|
|
147
147
|
if [ "$PENDING_TASKS" -gt 0 ]; then
|
148
148
|
echo ""
|
149
149
|
echo "NEXT_TASKS_PREVIEW:"
|
150
|
-
|
150
|
+
awk '/^### T[0-9]{3}:/{task=$0; found=0; for(i=0; i<5; i++) {getline; if(/^\*\*Status\*\*: \[ \]/) {found=1; break} if(/^###/) break} if(found) {print task; count++; if(count>=5) exit}}' "$TASK_FILE" | while read -r line; do
|
151
151
|
echo " $line"
|
152
152
|
done
|
153
153
|
fi
|
@@ -78,27 +78,30 @@ try {
|
|
78
78
|
$specContent = @"
|
79
79
|
# Specification for $FeatureName
|
80
80
|
|
81
|
-
<!--
|
82
|
-
<!--
|
83
|
-
<!--
|
81
|
+
<!-- INSTRUCTION: Generate specification content using template: $TemplateDir\spec.md -->
|
82
|
+
<!-- FEATURE_DIR: $BranchName -->
|
83
|
+
<!-- FEATURE_ID: $FeatureId -->
|
84
84
|
"@
|
85
85
|
Set-Content -Path "$SpecsDir\spec-001.md" -Value $specContent
|
86
86
|
|
87
87
|
$planContent = @"
|
88
88
|
# Implementation Plan for $FeatureName
|
89
89
|
|
90
|
-
<!--
|
91
|
-
<!--
|
92
|
-
<!--
|
90
|
+
<!-- INSTRUCTION: Generate plan using template: $TemplateDir\plan.md -->
|
91
|
+
<!-- SPEC_FILE: $SpecsDir\spec-001.md -->
|
92
|
+
<!-- FEATURE_DIR: $BranchName -->
|
93
|
+
<!-- FEATURE_ID: $FeatureId -->
|
93
94
|
"@
|
94
95
|
Set-Content -Path "$PlansDir\plan-001.md" -Value $planContent
|
95
96
|
|
96
97
|
$taskContent = @"
|
97
98
|
# Task Breakdown for $FeatureName
|
98
99
|
|
99
|
-
<!--
|
100
|
-
<!--
|
101
|
-
<!--
|
100
|
+
<!-- INSTRUCTION: Generate tasks using template: $TemplateDir\task.md -->
|
101
|
+
<!-- SPEC_FILE: $SpecsDir\spec-001.md -->
|
102
|
+
<!-- PLAN_FILE: $PlansDir\plan-001.md -->
|
103
|
+
<!-- FEATURE_DIR: $BranchName -->
|
104
|
+
<!-- FEATURE_ID: $FeatureId -->
|
102
105
|
"@
|
103
106
|
Set-Content -Path "$TasksDir\task-001.md" -Value $taskContent
|
104
107
|
} catch {
|
@@ -73,19 +73,22 @@ echo "# Task Breakdown for $FEATURE_NAME" > "$TASKS_DIR/task-001.md"
|
|
73
73
|
|
74
74
|
# Add markers indicating these files need AI processing
|
75
75
|
echo "" >> "$SPECS_DIR/spec-001.md"
|
76
|
-
echo "<!--
|
77
|
-
echo "<!--
|
78
|
-
echo "<!--
|
76
|
+
echo "<!-- INSTRUCTION: Generate specification content using template: $TEMPLATE_DIR/spec.md -->" >> "$SPECS_DIR/spec-001.md"
|
77
|
+
echo "<!-- FEATURE_DIR: $BRANCH_NAME -->" >> "$SPECS_DIR/spec-001.md"
|
78
|
+
echo "<!-- FEATURE_ID: $FEATURE_ID -->" >> "$SPECS_DIR/spec-001.md"
|
79
79
|
|
80
80
|
echo "" >> "$PLANS_DIR/plan-001.md"
|
81
|
-
echo "<!--
|
82
|
-
echo "<!--
|
83
|
-
echo "<!--
|
81
|
+
echo "<!-- INSTRUCTION: Generate plan using template: $TEMPLATE_DIR/plan.md -->" >> "$PLANS_DIR/plan-001.md"
|
82
|
+
echo "<!-- SPEC_FILE: $SPECS_DIR/spec-001.md -->" >> "$PLANS_DIR/plan-001.md"
|
83
|
+
echo "<!-- FEATURE_DIR: $BRANCH_NAME -->" >> "$PLANS_DIR/plan-001.md"
|
84
|
+
echo "<!-- FEATURE_ID: $FEATURE_ID -->" >> "$PLANS_DIR/plan-001.md"
|
84
85
|
|
85
86
|
echo "" >> "$TASKS_DIR/task-001.md"
|
86
|
-
echo "<!--
|
87
|
-
echo "<!--
|
88
|
-
echo "<!--
|
87
|
+
echo "<!-- INSTRUCTION: Generate tasks using template: $TEMPLATE_DIR/task.md -->" >> "$TASKS_DIR/task-001.md"
|
88
|
+
echo "<!-- SPEC_FILE: $SPECS_DIR/spec-001.md -->" >> "$TASKS_DIR/task-001.md"
|
89
|
+
echo "<!-- PLAN_FILE: $PLANS_DIR/plan-001.md -->" >> "$TASKS_DIR/task-001.md"
|
90
|
+
echo "<!-- FEATURE_DIR: $BRANCH_NAME -->" >> "$TASKS_DIR/task-001.md"
|
91
|
+
echo "<!-- FEATURE_ID: $FEATURE_ID -->" >> "$TASKS_DIR/task-001.md"
|
89
92
|
|
90
93
|
# Update context
|
91
94
|
CONTEXT_FILE="$PROJECT_ROOT/memory/context.md"
|
@@ -57,9 +57,20 @@ if (Test-Path $SpecDir) {
|
|
57
57
|
Exit-WithError "Specifications directory not found: $SpecDir. Please create specification first."
|
58
58
|
}
|
59
59
|
|
60
|
-
#
|
61
|
-
$
|
62
|
-
|
60
|
+
# Check if plan-001.md exists
|
61
|
+
$FirstPlan = Join-Path $PlanDir "plan-001.md"
|
62
|
+
if (Test-Path $FirstPlan) {
|
63
|
+
# Find next available plan number
|
64
|
+
$existingPlans = Get-ChildItem -Path $PlanDir -Filter "plan-*.md" -ErrorAction SilentlyContinue | Sort-Object Name
|
65
|
+
if ($existingPlans) {
|
66
|
+
$highestPlan = [int]($existingPlans[-1].BaseName -replace 'plan-', '')
|
67
|
+
$planNumber = $highestPlan + 1
|
68
|
+
} else {
|
69
|
+
$planNumber = 2
|
70
|
+
}
|
71
|
+
} else {
|
72
|
+
$planNumber = 1
|
73
|
+
}
|
63
74
|
$PlanFile = Join-Path $PlanDir ("plan-{0:D3}.md" -f $planNumber)
|
64
75
|
|
65
76
|
# Ensure plan template exists
|
@@ -67,36 +78,50 @@ if (-not (Test-Path $TemplateFile)) {
|
|
67
78
|
Exit-WithError "Template not found: $TemplateFile"
|
68
79
|
}
|
69
80
|
|
70
|
-
# Create plan
|
71
|
-
Log-Message "Creating implementation plan
|
81
|
+
# Create placeholder file for AI to generate plan
|
82
|
+
Log-Message "Creating implementation plan: $PlanFile"
|
72
83
|
try {
|
73
|
-
|
84
|
+
@"
|
85
|
+
# Implementation Plan - $FeatureDir
|
86
|
+
|
87
|
+
<!-- INSTRUCTION: Generate plan using template: $TemplateFile -->
|
88
|
+
<!-- SPEC_FILE: $SpecFile -->
|
89
|
+
<!-- FEATURE_DIR: $FeatureDir -->
|
90
|
+
<!-- FEATURE_ID: $FeatureId -->
|
91
|
+
"@ | Set-Content -Path $PlanFile
|
74
92
|
} catch {
|
75
|
-
Exit-WithError "Failed to
|
93
|
+
Exit-WithError "Failed to create plan file: $_"
|
76
94
|
}
|
77
95
|
|
78
96
|
# Validate plan structure
|
79
97
|
Log-Message "Validating implementation plan..."
|
80
98
|
|
81
|
-
# Check
|
82
|
-
$RequiredSections = @(
|
83
|
-
"## Implementation Plan:",
|
84
|
-
"## Specification Reference",
|
85
|
-
"## Phase -1: Pre-Implementation Gates",
|
86
|
-
"## Implementation Phases"
|
87
|
-
)
|
88
|
-
|
99
|
+
# Check if file needs AI generation
|
89
100
|
$content = Get-Content -Path $PlanFile -Raw
|
90
|
-
$
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
101
|
+
if ($content -match "INSTRUCTION: Generate plan") {
|
102
|
+
Log-Message "WARNING: Plan needs to be generated by AI from template"
|
103
|
+
$MissingSections = @("ALL - Awaiting AI Generation")
|
104
|
+
$GateStatus = "PENDING"
|
105
|
+
} else {
|
106
|
+
# Check for required sections only if file has been generated
|
107
|
+
$RequiredSections = @(
|
108
|
+
"## Implementation Plan:",
|
109
|
+
"## Specification Reference",
|
110
|
+
"## Phase -1: Pre-Implementation Gates",
|
111
|
+
"## Implementation Phases"
|
112
|
+
)
|
113
|
+
|
114
|
+
$MissingSections = @()
|
115
|
+
|
116
|
+
foreach ($section in $RequiredSections) {
|
117
|
+
if ($content -notmatch [regex]::Escape($section)) {
|
118
|
+
$MissingSections += $section
|
119
|
+
}
|
95
120
|
}
|
96
|
-
}
|
97
121
|
|
98
|
-
if ($MissingSections.Count -gt 0) {
|
99
|
-
|
122
|
+
if ($MissingSections.Count -gt 0) {
|
123
|
+
Log-Message "WARNING: Missing required sections: $($MissingSections -join ', ')"
|
124
|
+
}
|
100
125
|
}
|
101
126
|
|
102
127
|
# Check SDD Gates
|
@@ -91,7 +91,7 @@ echo "<!-- FEATURE_ID: $FEATURE_ID -->" >> "$PLAN_FILE"
|
|
91
91
|
log "Validating implementation plan..."
|
92
92
|
|
93
93
|
# Check if file needs AI generation
|
94
|
-
if grep -q "
|
94
|
+
if grep -q "INSTRUCTION: Generate plan" "$PLAN_FILE"; then
|
95
95
|
log "WARNING: Plan needs to be generated by AI from template"
|
96
96
|
MISSING_SECTIONS=("ALL - Awaiting AI Generation")
|
97
97
|
GATE_STATUS="PENDING"
|
@@ -77,12 +77,31 @@ if ($SpecContent) {
|
|
77
77
|
} else {
|
78
78
|
$specNumber = 2
|
79
79
|
}
|
80
|
+
$SpecFile = Join-Path $SpecDir ("spec-{0:D3}.md" -f $specNumber)
|
81
|
+
Log-Message "Creating specification file for AI generation: $SpecFile"
|
82
|
+
# Create placeholder file for AI to fill
|
83
|
+
$placeholderContent = @"
|
84
|
+
# Specification - $FeatureDir
|
85
|
+
|
86
|
+
<!-- INSTRUCTION: Generate specification content using template: $TemplateFile -->
|
87
|
+
<!-- FEATURE_DIR: $FeatureDir -->
|
88
|
+
<!-- FEATURE_ID: $FeatureId -->
|
89
|
+
"@
|
90
|
+
Set-Content -Path $SpecFile -Value $placeholderContent
|
80
91
|
} else {
|
81
|
-
|
92
|
+
# Create first spec
|
93
|
+
$SpecFile = Join-Path $SpecDir "spec-001.md"
|
94
|
+
Log-Message "Creating first specification file for AI generation: $SpecFile"
|
95
|
+
# Create placeholder file for AI to fill
|
96
|
+
$placeholderContent = @"
|
97
|
+
# Specification - $FeatureDir
|
98
|
+
|
99
|
+
<!-- INSTRUCTION: Generate specification content using template: $TemplateFile -->
|
100
|
+
<!-- FEATURE_DIR: $FeatureDir -->
|
101
|
+
<!-- FEATURE_ID: $FeatureId -->
|
102
|
+
"@
|
103
|
+
Set-Content -Path $SpecFile -Value $placeholderContent
|
82
104
|
}
|
83
|
-
$SpecFile = Join-Path $SpecDir ("spec-{0:D3}.md" -f $specNumber)
|
84
|
-
Log-Message "Creating specification file for AI generation: $SpecFile"
|
85
|
-
"INSTRUCTION: Generate specification content using template at $TemplateFile" | Set-Content -Path "$SpecFile.instruction"
|
86
105
|
}
|
87
106
|
|
88
107
|
# Validate specification
|
@@ -91,25 +110,31 @@ if (-not (Test-Path $SpecFile)) {
|
|
91
110
|
Exit-WithError "Specification file does not exist: $SpecFile"
|
92
111
|
}
|
93
112
|
|
94
|
-
# Check
|
95
|
-
$RequiredSections = @(
|
96
|
-
"## Specification:",
|
97
|
-
"## Metadata",
|
98
|
-
"## Functional Requirements",
|
99
|
-
"## Acceptance Scenarios"
|
100
|
-
)
|
101
|
-
|
113
|
+
# Check if file needs AI generation
|
102
114
|
$content = Get-Content -Path $SpecFile -Raw
|
103
|
-
$
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
115
|
+
if ($content -match "INSTRUCTION: Generate specification") {
|
116
|
+
Log-Message "WARNING: Specification needs to be generated by AI from template"
|
117
|
+
$MissingSections = @("ALL - Awaiting AI Generation")
|
118
|
+
} else {
|
119
|
+
# Check for required sections only if file has been generated
|
120
|
+
$RequiredSections = @(
|
121
|
+
"## Specification:",
|
122
|
+
"## Metadata",
|
123
|
+
"## Functional Requirements",
|
124
|
+
"## Acceptance Scenarios"
|
125
|
+
)
|
126
|
+
|
127
|
+
$MissingSections = @()
|
128
|
+
|
129
|
+
foreach ($section in $RequiredSections) {
|
130
|
+
if ($content -notmatch [regex]::Escape($section)) {
|
131
|
+
$MissingSections += $section
|
132
|
+
}
|
108
133
|
}
|
109
|
-
}
|
110
134
|
|
111
|
-
if ($MissingSections.Count -gt 0) {
|
112
|
-
|
135
|
+
if ($MissingSections.Count -gt 0) {
|
136
|
+
Log-Message "WARNING: Missing required sections: $($MissingSections -join ', ')"
|
137
|
+
}
|
113
138
|
}
|
114
139
|
|
115
140
|
# Check for clarifications needed
|
@@ -107,7 +107,7 @@ if [ ! -f "$SPEC_FILE" ]; then
|
|
107
107
|
fi
|
108
108
|
|
109
109
|
# Check if file needs AI generation
|
110
|
-
if grep -q "
|
110
|
+
if grep -q "INSTRUCTION: Generate specification" "$SPEC_FILE"; then
|
111
111
|
log "WARNING: Specification needs to be generated by AI from template"
|
112
112
|
MISSING_SECTIONS=("ALL - Awaiting AI Generation")
|
113
113
|
else
|
@@ -72,9 +72,20 @@ if (Test-Path $PlanDir) {
|
|
72
72
|
Exit-WithError "Plans directory not found: $PlanDir. Please create plan first."
|
73
73
|
}
|
74
74
|
|
75
|
-
#
|
76
|
-
$
|
77
|
-
|
75
|
+
# Check if task-001.md exists
|
76
|
+
$FirstTask = Join-Path $TaskDir "task-001.md"
|
77
|
+
if (Test-Path $FirstTask) {
|
78
|
+
# Find next available task number
|
79
|
+
$existingTasks = Get-ChildItem -Path $TaskDir -Filter "task-*.md" -ErrorAction SilentlyContinue | Sort-Object Name
|
80
|
+
if ($existingTasks) {
|
81
|
+
$highestTask = [int]($existingTasks[-1].BaseName -replace 'task-', '')
|
82
|
+
$taskNumber = $highestTask + 1
|
83
|
+
} else {
|
84
|
+
$taskNumber = 2
|
85
|
+
}
|
86
|
+
} else {
|
87
|
+
$taskNumber = 1
|
88
|
+
}
|
78
89
|
$TaskFile = Join-Path $TaskDir ("task-{0:D3}.md" -f $taskNumber)
|
79
90
|
|
80
91
|
# Ensure task template exists
|
@@ -82,46 +93,65 @@ if (-not (Test-Path $TemplateFile)) {
|
|
82
93
|
Exit-WithError "Template not found: $TemplateFile"
|
83
94
|
}
|
84
95
|
|
85
|
-
# Create
|
86
|
-
Log-Message "Creating task breakdown
|
96
|
+
# Create placeholder file for AI to generate tasks
|
97
|
+
Log-Message "Creating task breakdown: $TaskFile"
|
87
98
|
try {
|
88
|
-
|
99
|
+
@"
|
100
|
+
# Task Breakdown - $FeatureDir
|
101
|
+
|
102
|
+
<!-- INSTRUCTION: Generate tasks using template: $TemplateFile -->
|
103
|
+
<!-- SPEC_FILE: $SpecFile -->
|
104
|
+
<!-- PLAN_FILE: $PlanFile -->
|
105
|
+
<!-- FEATURE_DIR: $FeatureDir -->
|
106
|
+
<!-- FEATURE_ID: $FeatureId -->
|
107
|
+
"@ | Set-Content -Path $TaskFile
|
89
108
|
} catch {
|
90
|
-
Exit-WithError "Failed to
|
109
|
+
Exit-WithError "Failed to create task file: $_"
|
91
110
|
}
|
92
111
|
|
93
112
|
# Validate task structure
|
94
113
|
Log-Message "Validating task breakdown..."
|
95
114
|
|
96
|
-
# Check
|
97
|
-
$RequiredSections = @(
|
98
|
-
"## Task List:",
|
99
|
-
"## Task Organization",
|
100
|
-
"## Critical Path",
|
101
|
-
"## Execution Schedule"
|
102
|
-
)
|
103
|
-
|
115
|
+
# Check if file needs AI generation
|
104
116
|
$content = Get-Content -Path $TaskFile -Raw
|
105
|
-
$
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
117
|
+
if ($content -match "INSTRUCTION: Generate tasks") {
|
118
|
+
Log-Message "WARNING: Tasks need to be generated by AI from template"
|
119
|
+
$MissingSections = @("ALL - Awaiting AI Generation")
|
120
|
+
$TotalTasks = 0
|
121
|
+
$CompletedTasks = 0
|
122
|
+
$PendingTasks = 0
|
123
|
+
$BlockedTasks = 0
|
124
|
+
$ParallelTasks = 0
|
125
|
+
} else {
|
126
|
+
# Check for required sections only if file has been generated
|
127
|
+
$RequiredSections = @(
|
128
|
+
"## Task List:",
|
129
|
+
"## Task Organization",
|
130
|
+
"## Critical Path",
|
131
|
+
"## Execution Schedule"
|
132
|
+
)
|
133
|
+
|
134
|
+
$MissingSections = @()
|
135
|
+
|
136
|
+
foreach ($section in $RequiredSections) {
|
137
|
+
if ($content -notmatch [regex]::Escape($section)) {
|
138
|
+
$MissingSections += $section
|
139
|
+
}
|
110
140
|
}
|
111
|
-
}
|
112
141
|
|
113
|
-
if ($MissingSections.Count -gt 0) {
|
114
|
-
|
115
|
-
}
|
142
|
+
if ($MissingSections.Count -gt 0) {
|
143
|
+
Log-Message "WARNING: Missing required sections: $($MissingSections -join ', ')"
|
144
|
+
}
|
116
145
|
|
117
|
-
# Count tasks and analyze structure
|
118
|
-
$TotalTasks = ([regex]::Matches($content, "^- \[.\]", [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
119
|
-
$CompletedTasks = ([regex]::Matches($content, "^- \[x\]", [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
120
|
-
$PendingTasks = ([regex]::Matches($content, "^- \[ \]", [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
121
|
-
$BlockedTasks = ([regex]::Matches($content, "^- \[!\]", [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
146
|
+
# Count tasks and analyze structure
|
147
|
+
$TotalTasks = ([regex]::Matches($content, "^- \[.\]", [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
148
|
+
$CompletedTasks = ([regex]::Matches($content, "^- \[x\]", [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
149
|
+
$PendingTasks = ([regex]::Matches($content, "^- \[ \]", [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
150
|
+
$BlockedTasks = ([regex]::Matches($content, "^- \[!\]", [System.Text.RegularExpressions.RegexOptions]::Multiline)).Count
|
122
151
|
|
123
|
-
# Check for parallel tasks
|
124
|
-
$ParallelTasks = ([regex]::Matches($content, "\[P\]")).Count
|
152
|
+
# Check for parallel tasks
|
153
|
+
$ParallelTasks = ([regex]::Matches($content, "\[P\]")).Count
|
154
|
+
}
|
125
155
|
|
126
156
|
# Check SDD gates compliance
|
127
157
|
$GatesCount = 0
|
@@ -103,7 +103,7 @@ echo "<!-- FEATURE_ID: $FEATURE_ID -->" >> "$TASK_FILE"
|
|
103
103
|
log "Validating task breakdown..."
|
104
104
|
|
105
105
|
# Check if file needs AI generation
|
106
|
-
if grep -q "
|
106
|
+
if grep -q "INSTRUCTION: Generate tasks" "$TASK_FILE"; then
|
107
107
|
log "WARNING: Tasks need to be generated by AI from template"
|
108
108
|
MISSING_SECTIONS=("ALL - Awaiting AI Generation")
|
109
109
|
TOTAL_TASKS=0
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: specpulse
|
3
|
-
Version: 1.4.
|
3
|
+
Version: 1.4.4
|
4
4
|
Summary: Specification-Driven Development Framework
|
5
5
|
Home-page: https://github.com/specpulse
|
6
6
|
Author: SpecPulse
|
@@ -67,7 +67,13 @@ Dynamic: requires-python
|
|
67
67
|
|
68
68
|
SpecPulse is a universal **Specification-Driven Development (SDD)** framework that works with ANY software project - web apps, mobile apps, desktop software, games, APIs, ML projects, and more. It ensures every feature starts with clear specifications, validated plans, and tracked tasks.
|
69
69
|
|
70
|
-
> **Latest Update (v1.4.
|
70
|
+
> **Latest Update (v1.4.4)** - Critical Workflow Fixes:
|
71
|
+
> - 🐛 **Fixed Script Numbering**: Resolved `/sp-pulse` creating empty placeholders while subsequent commands created new files
|
72
|
+
> - 🎯 **Fixed Task Detection**: Execute scripts now properly detect task format (`### T001:` with `**Status**:`)
|
73
|
+
> - 📝 **Unified Placeholders**: All scripts use consistent `<!-- INSTRUCTION: Generate -->` markers
|
74
|
+
> - 🔧 **PowerShell Parity**: PowerShell scripts now match Bash behavior exactly
|
75
|
+
>
|
76
|
+
> **v1.4.3** - Script Numbering Fix:
|
71
77
|
> - 🔢 **Fixed Numbering Logic**: Spec, plan, and task files now number correctly (001, 002, 003...)
|
72
78
|
> - 📝 **No Empty First Files**: spec-001.md, plan-001.md, task-001.md always contain content
|
73
79
|
> - 🎯 **Proper Interactive Mode**: Scripts create placeholder files for AI to fill
|
@@ -25,16 +25,16 @@ specpulse/resources/memory/context.md,sha256=B-6m5f4WP8x_VXp0S9fbqm8tHH-2PZ7d9VW
|
|
25
25
|
specpulse/resources/memory/decisions.md,sha256=ZwzVyOPB2mIzwveWpGmedej7ncI81GALg8WVy6AeZA4,686
|
26
26
|
specpulse/resources/scripts/sp-pulse-decompose.ps1,sha256=KVrcDHYxibCyzY_Z9SKo7gMdM8mfKY7RukUPKVCaJ_A,2376
|
27
27
|
specpulse/resources/scripts/sp-pulse-decompose.sh,sha256=EN8iF02pij4yse3of3fgO8ZI6YKFUV7Z7f4epEmaKXI,1431
|
28
|
-
specpulse/resources/scripts/sp-pulse-execute.ps1,sha256=
|
29
|
-
specpulse/resources/scripts/sp-pulse-execute.sh,sha256=
|
30
|
-
specpulse/resources/scripts/sp-pulse-init.ps1,sha256=
|
31
|
-
specpulse/resources/scripts/sp-pulse-init.sh,sha256
|
32
|
-
specpulse/resources/scripts/sp-pulse-plan.ps1,sha256=
|
33
|
-
specpulse/resources/scripts/sp-pulse-plan.sh,sha256=
|
34
|
-
specpulse/resources/scripts/sp-pulse-spec.ps1,sha256=
|
35
|
-
specpulse/resources/scripts/sp-pulse-spec.sh,sha256=
|
36
|
-
specpulse/resources/scripts/sp-pulse-task.ps1,sha256=
|
37
|
-
specpulse/resources/scripts/sp-pulse-task.sh,sha256=
|
28
|
+
specpulse/resources/scripts/sp-pulse-execute.ps1,sha256=EBhAC91_z_0gu8YdHR24w6pv33DmCPXVeqkwbgVmRVw,7182
|
29
|
+
specpulse/resources/scripts/sp-pulse-execute.sh,sha256=M5XE1k4fUd5yhM1h6NdWHUcG9pA319VRovKkmQJMgws,6136
|
30
|
+
specpulse/resources/scripts/sp-pulse-init.ps1,sha256=6A0foYeBC-CBQaFb0qXxOx6T-QAzgzFTQbrq5EUiBs4,5015
|
31
|
+
specpulse/resources/scripts/sp-pulse-init.sh,sha256=-iGJPQJpJVclEetrpUNxkSDs6pwGmi7bQ7zBswEhlUQ,4692
|
32
|
+
specpulse/resources/scripts/sp-pulse-plan.ps1,sha256=a9o167yy0wYZSr4Fg3wCP0p3daZMoDsgpZrwo0wKGM0,5175
|
33
|
+
specpulse/resources/scripts/sp-pulse-plan.sh,sha256=hjy37mOC1hF2I__YwNA7bXJ9qV90kiuAPHnVBVvb-yA,4854
|
34
|
+
specpulse/resources/scripts/sp-pulse-spec.ps1,sha256=V4pFC9d7OX-x3aPjXrrCW7GTn1eEE5-3wZK1z_xBf0U,5271
|
35
|
+
specpulse/resources/scripts/sp-pulse-spec.sh,sha256=WJeAeQdc70ynK8bZNkHuul_d_splurqS5_Oi_2Dw2l8,5154
|
36
|
+
specpulse/resources/scripts/sp-pulse-task.ps1,sha256=Q9YQYINkCX9tCXvGlvuA974PRdNPqRaaaH7KzaQvRps,6604
|
37
|
+
specpulse/resources/scripts/sp-pulse-task.sh,sha256=LxdiObEakOi01IZq1kVeikDXuhRjYplFvgn4gv97Uts,5865
|
38
38
|
specpulse/resources/templates/plan.md,sha256=ieouqeIhLEfzP-_vytCmKHqxNGh8ITNZ5sub3nufvZ0,3349
|
39
39
|
specpulse/resources/templates/spec.md,sha256=wGXSyD7AWRofeeW5a2rVrSIxeYK5zolQulN1xJRni44,2234
|
40
40
|
specpulse/resources/templates/task.md,sha256=X3_BOYIZ40qMGRxDs-stGh0pAVyZHYkvSNuvXJO981o,4658
|
@@ -47,9 +47,9 @@ specpulse/utils/__init__.py,sha256=VTGRDsVLl2JIXYyHB9Sidxj5acY_W-LJI2MMtY1pwb0,1
|
|
47
47
|
specpulse/utils/console.py,sha256=1Dn6m81dZa3XZkeKvGFgQywE9FyQnhlOorNtE0f86VM,14793
|
48
48
|
specpulse/utils/git_utils.py,sha256=jH5RWbC-lx2iPKVm2dWP7Iqqh1_CdmbNi7q4S_c4W8s,7393
|
49
49
|
specpulse/utils/version_check.py,sha256=9Ug0Td1SesRskx2JFy7QS59ikomKRxuSM9OUHrZtEO4,3877
|
50
|
-
specpulse-1.4.
|
51
|
-
specpulse-1.4.
|
52
|
-
specpulse-1.4.
|
53
|
-
specpulse-1.4.
|
54
|
-
specpulse-1.4.
|
55
|
-
specpulse-1.4.
|
50
|
+
specpulse-1.4.4.dist-info/licenses/LICENSE,sha256=ImSFezK-Phy0oTBqZipcajsJfPZT8mmg8m3jkgNdNhA,1066
|
51
|
+
specpulse-1.4.4.dist-info/METADATA,sha256=EP9APXO6hQn84PeIuh-8bbBA7n9RwKRfpr6-0jqrJIY,25134
|
52
|
+
specpulse-1.4.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
53
|
+
specpulse-1.4.4.dist-info/entry_points.txt,sha256=GwMaCKWSCFZlJMrTNavEYrnREynIS6dM3B0ILxnaouA,83
|
54
|
+
specpulse-1.4.4.dist-info/top_level.txt,sha256=pEfkFil5xe38J00OHrBrJ07xpbm6bRnGhI8B07O9KeI,10
|
55
|
+
specpulse-1.4.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|