specpulse 1.0.3__py3-none-any.whl → 1.0.5__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/resources/commands/claude/plan.md +180 -50
- specpulse/resources/commands/claude/pulse.md +79 -24
- specpulse/resources/commands/claude/spec.md +156 -43
- specpulse/resources/commands/claude/task.md +229 -48
- specpulse/resources/commands/gemini/plan.toml +59 -48
- specpulse/resources/commands/gemini/pulse.toml +21 -39
- specpulse/resources/commands/gemini/spec.toml +40 -28
- specpulse/resources/commands/gemini/task.toml +69 -51
- specpulse/resources/memory/constitution.md +2 -2
- specpulse/resources/scripts/pulse-init.ps1 +186 -0
- specpulse/resources/scripts/pulse-init.py +171 -0
- specpulse/resources/scripts/pulse-init.sh +80 -21
- specpulse/resources/scripts/pulse-plan.ps1 +251 -0
- specpulse/resources/scripts/pulse-plan.py +191 -0
- specpulse/resources/scripts/pulse-plan.sh +113 -12
- specpulse/resources/scripts/pulse-spec.ps1 +185 -0
- specpulse/resources/scripts/pulse-spec.py +167 -0
- specpulse/resources/scripts/pulse-spec.sh +86 -11
- specpulse/resources/scripts/pulse-task.ps1 +263 -0
- specpulse/resources/scripts/pulse-task.py +237 -0
- specpulse/resources/scripts/pulse-task.sh +123 -9
- specpulse/resources/templates/plan.md +142 -287
- specpulse/resources/templates/spec.md +80 -246
- specpulse/resources/templates/task.md +114 -93
- {specpulse-1.0.3.dist-info → specpulse-1.0.5.dist-info}/METADATA +67 -34
- specpulse-1.0.5.dist-info/RECORD +41 -0
- specpulse-1.0.3.dist-info/RECORD +0 -33
- {specpulse-1.0.3.dist-info → specpulse-1.0.5.dist-info}/WHEEL +0 -0
- {specpulse-1.0.3.dist-info → specpulse-1.0.5.dist-info}/entry_points.txt +0 -0
- {specpulse-1.0.3.dist-info → specpulse-1.0.5.dist-info}/licenses/LICENSE +0 -0
- {specpulse-1.0.3.dist-info → specpulse-1.0.5.dist-info}/top_level.txt +0 -0
@@ -124,7 +124,7 @@ complexity_exceptions:
|
|
124
124
|
violation: "Using 4 projects instead of 3"
|
125
125
|
justification: "Authentication requires separate service for security isolation"
|
126
126
|
approved_by: "Team Lead"
|
127
|
-
date: "
|
127
|
+
date: "2025-09-11"
|
128
128
|
```
|
129
129
|
|
130
130
|
### Amendment Process
|
@@ -233,5 +233,5 @@ While principles are immutable, their application can evolve:
|
|
233
233
|
## Living Constitution
|
234
234
|
This constitution is a living document that learns from experience while maintaining core principles. Each project iteration strengthens these principles through practical application and refinement.
|
235
235
|
|
236
|
-
*Last Updated:
|
236
|
+
*Last Updated: 2025-09-11*
|
237
237
|
*Version: 2.0 - Full SDD Methodology Implementation*
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# SpecPulse Feature Initialization Script
|
2
|
+
# Cross-platform PowerShell equivalent of pulse-init.sh
|
3
|
+
|
4
|
+
param(
|
5
|
+
[Parameter(Mandatory=$true)]
|
6
|
+
[string]$FeatureName,
|
7
|
+
|
8
|
+
[string]$CustomId = ""
|
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-FeatureName {
|
34
|
+
param([string]$Name)
|
35
|
+
|
36
|
+
if ([string]::IsNullOrWhiteSpace($Name)) {
|
37
|
+
Exit-WithError "Feature name cannot be empty"
|
38
|
+
}
|
39
|
+
|
40
|
+
# Convert to lowercase, replace spaces and special chars with hyphens
|
41
|
+
$Sanitized = $Name.ToLower() -replace '[^a-z0-9-]', '-'
|
42
|
+
$Sanitized = $Sanitized -replace '-+', '-' # Remove consecutive hyphens
|
43
|
+
$Sanitized = $Sanitized.Trim('-') # Remove leading/trailing hyphens
|
44
|
+
|
45
|
+
if ([string]::IsNullOrWhiteSpace($Sanitized)) {
|
46
|
+
Exit-WithError "Invalid feature name: '$Name'"
|
47
|
+
}
|
48
|
+
|
49
|
+
return $Sanitized
|
50
|
+
}
|
51
|
+
|
52
|
+
function Get-FeatureId {
|
53
|
+
param([string]$CustomId)
|
54
|
+
|
55
|
+
if ($CustomId) {
|
56
|
+
return "{0:D3}" -f [int]$CustomId
|
57
|
+
}
|
58
|
+
|
59
|
+
# Find existing feature directories
|
60
|
+
$SpecsDir = Join-Path $ProjectRoot "specs"
|
61
|
+
if (Test-Path $SpecsDir) {
|
62
|
+
$Existing = Get-ChildItem -Path $SpecsDir -Directory |
|
63
|
+
Where-Object { $_.Name -match '^\d+$' } |
|
64
|
+
Sort-Object Name
|
65
|
+
$NextId = $Existing.Count + 1
|
66
|
+
} else {
|
67
|
+
$NextId = 1
|
68
|
+
}
|
69
|
+
|
70
|
+
return "{0:D3}" -f $NextId
|
71
|
+
}
|
72
|
+
|
73
|
+
function Create-Directories {
|
74
|
+
param([string]$BranchName)
|
75
|
+
|
76
|
+
$Directories = @(
|
77
|
+
(Join-Path $ProjectRoot "specs" $BranchName),
|
78
|
+
(Join-Path $ProjectRoot "plans" $BranchName),
|
79
|
+
(Join-Path $ProjectRoot "tasks" $BranchName)
|
80
|
+
)
|
81
|
+
|
82
|
+
foreach ($Directory in $Directories) {
|
83
|
+
try {
|
84
|
+
New-Item -ItemType Directory -Path $Directory -Force | Out-Null
|
85
|
+
Write-Log "Created directory: $Directory"
|
86
|
+
} catch {
|
87
|
+
Exit-WithError "Failed to create directory $Directory : $_"
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
function Copy-Templates {
|
93
|
+
param([string]$BranchName)
|
94
|
+
|
95
|
+
$Templates = @{
|
96
|
+
"spec.md" = (Join-Path $ProjectRoot "specs" $BranchName "spec.md")
|
97
|
+
"plan.md" = (Join-Path $ProjectRoot "plans" $BranchName "plan.md")
|
98
|
+
"task.md" = (Join-Path $ProjectRoot "tasks" $BranchName "tasks.md")
|
99
|
+
}
|
100
|
+
|
101
|
+
foreach ($Template in $Templates.GetEnumerator()) {
|
102
|
+
$TemplatePath = Join-Path $TemplatesDir $Template.Key
|
103
|
+
$TargetPath = $Template.Value
|
104
|
+
|
105
|
+
if (-not (Test-Path $TemplatePath)) {
|
106
|
+
Exit-WithError "Template not found: $TemplatePath"
|
107
|
+
}
|
108
|
+
|
109
|
+
try {
|
110
|
+
Copy-Item $TemplatePath $TargetPath -Force
|
111
|
+
Write-Log "Copied template to: $TargetPath"
|
112
|
+
} catch {
|
113
|
+
Exit-WithError "Failed to copy template $TemplatePath : $_"
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
function Update-Context {
|
119
|
+
param(
|
120
|
+
[string]$FeatureName,
|
121
|
+
[string]$FeatureId,
|
122
|
+
[string]$BranchName
|
123
|
+
)
|
124
|
+
|
125
|
+
try {
|
126
|
+
New-Item -ItemType Directory -Path $MemoryDir -Force | Out-Null
|
127
|
+
|
128
|
+
$ContextEntry = @"
|
129
|
+
|
130
|
+
## Active Feature: $FeatureName
|
131
|
+
- Feature ID: $FeatureId
|
132
|
+
- Branch: $BranchName
|
133
|
+
- Started: $(Get-Date -Format "o")
|
134
|
+
"@
|
135
|
+
|
136
|
+
Add-Content -Path $ContextFile -Value $ContextEntry -Encoding UTF8
|
137
|
+
Write-Log "Updated context file: $ContextFile"
|
138
|
+
} catch {
|
139
|
+
Exit-WithError "Failed to update context file: $_"
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
function New-GitBranch {
|
144
|
+
param([string]$BranchName)
|
145
|
+
|
146
|
+
$GitDir = Join-Path $ProjectRoot ".git"
|
147
|
+
if (-not (Test-Path $GitDir)) {
|
148
|
+
return
|
149
|
+
}
|
150
|
+
|
151
|
+
try {
|
152
|
+
# Check if branch already exists
|
153
|
+
$ExistingBranch = git branch --list $BranchName
|
154
|
+
if ($ExistingBranch) {
|
155
|
+
Write-Log "Git branch '$BranchName' already exists, checking out"
|
156
|
+
git checkout $BranchName
|
157
|
+
} else {
|
158
|
+
Write-Log "Creating new git branch '$BranchName'"
|
159
|
+
git checkout -b $BranchName
|
160
|
+
}
|
161
|
+
} catch {
|
162
|
+
Exit-WithError "Git operation failed: $_"
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
# Main execution
|
167
|
+
Write-Log "Initializing feature: $FeatureName"
|
168
|
+
|
169
|
+
# Sanitize and generate identifiers
|
170
|
+
$SanitizedName = Sanitize-FeatureName -Name $FeatureName
|
171
|
+
$FeatureId = Get-FeatureId -CustomId $CustomId
|
172
|
+
$BranchName = "$FeatureId-$SanitizedName"
|
173
|
+
|
174
|
+
# Create structure
|
175
|
+
Create-Directories -BranchName $BranchName
|
176
|
+
Copy-Templates -BranchName $BranchName
|
177
|
+
Update-Context -FeatureName $FeatureName -FeatureId $FeatureId -BranchName $BranchName
|
178
|
+
New-GitBranch -BranchName $BranchName
|
179
|
+
|
180
|
+
# Output results
|
181
|
+
Write-Host "BRANCH_NAME=$BranchName"
|
182
|
+
Write-Host "SPEC_DIR=specs/$BranchName"
|
183
|
+
Write-Host "FEATURE_ID=$FeatureId"
|
184
|
+
Write-Host "STATUS=initialized"
|
185
|
+
|
186
|
+
Write-Log "Successfully initialized feature '$FeatureName' with ID $FeatureId"
|
@@ -0,0 +1,171 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
SpecPulse Feature Initialization Script
|
4
|
+
Cross-platform Python equivalent of pulse-init.sh
|
5
|
+
"""
|
6
|
+
|
7
|
+
import os
|
8
|
+
import sys
|
9
|
+
import subprocess
|
10
|
+
import re
|
11
|
+
import datetime
|
12
|
+
from pathlib import Path
|
13
|
+
|
14
|
+
class SpecPulseInit:
|
15
|
+
def __init__(self):
|
16
|
+
self.script_name = Path(__file__).name
|
17
|
+
self.project_root = Path(__file__).parent.parent.parent
|
18
|
+
self.memory_dir = self.project_root / "memory"
|
19
|
+
self.context_file = self.memory_dir / "context.md"
|
20
|
+
self.templates_dir = self.project_root / "resources" / "templates"
|
21
|
+
|
22
|
+
def log(self, message):
|
23
|
+
"""Log messages with timestamp"""
|
24
|
+
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
25
|
+
print(f"[{timestamp}] {self.script_name}: {message}", file=sys.stderr)
|
26
|
+
|
27
|
+
def error_exit(self, message):
|
28
|
+
"""Exit with error message"""
|
29
|
+
self.log(f"ERROR: {message}")
|
30
|
+
sys.exit(1)
|
31
|
+
|
32
|
+
def sanitize_feature_name(self, feature_name):
|
33
|
+
"""Sanitize feature name for safe directory naming"""
|
34
|
+
if not feature_name:
|
35
|
+
self.error_exit("Feature name cannot be empty")
|
36
|
+
|
37
|
+
# Convert to lowercase, replace spaces and special chars with hyphens
|
38
|
+
sanitized = re.sub(r'[^a-z0-9-]', '-', feature_name.lower())
|
39
|
+
sanitized = re.sub(r'-+', '-', sanitized) # Remove consecutive hyphens
|
40
|
+
sanitized = sanitized.strip('-') # Remove leading/trailing hyphens
|
41
|
+
|
42
|
+
if not sanitized:
|
43
|
+
self.error_exit(f"Invalid feature name: '{feature_name}'")
|
44
|
+
|
45
|
+
return sanitized
|
46
|
+
|
47
|
+
def get_feature_id(self, custom_id=None):
|
48
|
+
"""Get next feature ID"""
|
49
|
+
if custom_id:
|
50
|
+
return f"{int(custom_id):03d}"
|
51
|
+
|
52
|
+
# Find existing feature directories
|
53
|
+
specs_dir = self.project_root / "specs"
|
54
|
+
if specs_dir.exists():
|
55
|
+
existing = [d for d in specs_dir.iterdir() if d.is_dir() and d.name.isdigit()]
|
56
|
+
next_id = len(existing) + 1
|
57
|
+
else:
|
58
|
+
next_id = 1
|
59
|
+
|
60
|
+
return f"{next_id:03d}"
|
61
|
+
|
62
|
+
def create_directories(self, branch_name):
|
63
|
+
"""Create feature directories"""
|
64
|
+
dirs_to_create = [
|
65
|
+
self.project_root / "specs" / branch_name,
|
66
|
+
self.project_root / "plans" / branch_name,
|
67
|
+
self.project_root / "tasks" / branch_name
|
68
|
+
]
|
69
|
+
|
70
|
+
for directory in dirs_to_create:
|
71
|
+
try:
|
72
|
+
directory.mkdir(parents=True, exist_ok=True)
|
73
|
+
self.log(f"Created directory: {directory}")
|
74
|
+
except Exception as e:
|
75
|
+
self.error_exit(f"Failed to create directory {directory}: {e}")
|
76
|
+
|
77
|
+
def copy_templates(self, branch_name):
|
78
|
+
"""Copy templates to feature directories"""
|
79
|
+
templates = {
|
80
|
+
"spec.md": self.project_root / "specs" / branch_name / "spec.md",
|
81
|
+
"plan.md": self.project_root / "plans" / branch_name / "plan.md",
|
82
|
+
"task.md": self.project_root / "tasks" / branch_name / "tasks.md"
|
83
|
+
}
|
84
|
+
|
85
|
+
for template_name, target_path in templates.items():
|
86
|
+
template_path = self.templates_dir / template_name
|
87
|
+
if not template_path.exists():
|
88
|
+
self.error_exit(f"Template not found: {template_path}")
|
89
|
+
|
90
|
+
try:
|
91
|
+
target_path.write_text(template_path.read_text())
|
92
|
+
self.log(f"Copied template to: {target_path}")
|
93
|
+
except Exception as e:
|
94
|
+
self.error_exit(f"Failed to copy template {template_path}: {e}")
|
95
|
+
|
96
|
+
def update_context(self, feature_name, feature_id, branch_name):
|
97
|
+
"""Update context file"""
|
98
|
+
try:
|
99
|
+
self.memory_dir.mkdir(parents=True, exist_ok=True)
|
100
|
+
|
101
|
+
context_entry = f"""
|
102
|
+
|
103
|
+
## Active Feature: {feature_name}
|
104
|
+
- Feature ID: {feature_id}
|
105
|
+
- Branch: {branch_name}
|
106
|
+
- Started: {datetime.datetime.now().isoformat()}
|
107
|
+
"""
|
108
|
+
|
109
|
+
with open(self.context_file, 'a', encoding='utf-8') as f:
|
110
|
+
f.write(context_entry)
|
111
|
+
|
112
|
+
self.log(f"Updated context file: {self.context_file}")
|
113
|
+
except Exception as e:
|
114
|
+
self.error_exit(f"Failed to update context file: {e}")
|
115
|
+
|
116
|
+
def create_git_branch(self, branch_name):
|
117
|
+
"""Create git branch if in git repository"""
|
118
|
+
git_dir = self.project_root / ".git"
|
119
|
+
if not git_dir.exists():
|
120
|
+
return
|
121
|
+
|
122
|
+
try:
|
123
|
+
# Check if branch already exists
|
124
|
+
result = subprocess.run(
|
125
|
+
["git", "branch", "--list", branch_name],
|
126
|
+
cwd=self.project_root,
|
127
|
+
capture_output=True,
|
128
|
+
text=True
|
129
|
+
)
|
130
|
+
|
131
|
+
if branch_name in result.stdout:
|
132
|
+
self.log(f"Git branch '{branch_name}' already exists, checking out")
|
133
|
+
subprocess.run(["git", "checkout", branch_name], cwd=self.project_root, check=True)
|
134
|
+
else:
|
135
|
+
self.log(f"Creating new git branch '{branch_name}'")
|
136
|
+
subprocess.run(["git", "checkout", "-b", branch_name], cwd=self.project_root, check=True)
|
137
|
+
except subprocess.CalledProcessError as e:
|
138
|
+
self.error_exit(f"Git operation failed: {e}")
|
139
|
+
|
140
|
+
def main(self, args):
|
141
|
+
"""Main execution function"""
|
142
|
+
if len(args) < 1:
|
143
|
+
self.error_exit("Usage: python pulse-init.py <feature-name> [feature-id]")
|
144
|
+
|
145
|
+
feature_name = args[0]
|
146
|
+
custom_id = args[1] if len(args) > 1 else None
|
147
|
+
|
148
|
+
self.log(f"Initializing feature: {feature_name}")
|
149
|
+
|
150
|
+
# Sanitize and generate identifiers
|
151
|
+
sanitized_name = self.sanitize_feature_name(feature_name)
|
152
|
+
feature_id = self.get_feature_id(custom_id)
|
153
|
+
branch_name = f"{feature_id}-{sanitized_name}"
|
154
|
+
|
155
|
+
# Create structure
|
156
|
+
self.create_directories(branch_name)
|
157
|
+
self.copy_templates(branch_name)
|
158
|
+
self.update_context(feature_name, feature_id, branch_name)
|
159
|
+
self.create_git_branch(branch_name)
|
160
|
+
|
161
|
+
# Output results
|
162
|
+
print(f"BRANCH_NAME={branch_name}")
|
163
|
+
print(f"SPEC_DIR=specs/{branch_name}")
|
164
|
+
print(f"FEATURE_ID={feature_id}")
|
165
|
+
print("STATUS=initialized")
|
166
|
+
|
167
|
+
self.log(f"Successfully initialized feature '{feature_name}' with ID {feature_id}")
|
168
|
+
|
169
|
+
if __name__ == "__main__":
|
170
|
+
init = SpecPulseInit()
|
171
|
+
init.main(sys.argv[1:])
|
@@ -1,37 +1,96 @@
|
|
1
1
|
#!/bin/bash
|
2
2
|
# Initialize a new feature with SpecPulse
|
3
3
|
|
4
|
-
|
4
|
+
set -euo pipefail # Exit on error, unset vars, pipe failures
|
5
5
|
|
6
|
-
#
|
7
|
-
|
6
|
+
# Configuration
|
7
|
+
SCRIPT_NAME="$(basename "$0")"
|
8
|
+
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
8
9
|
|
9
|
-
#
|
10
|
-
|
10
|
+
# Function to log messages
|
11
|
+
log() {
|
12
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $SCRIPT_NAME: $1" >&2
|
13
|
+
}
|
14
|
+
|
15
|
+
# Function to handle errors
|
16
|
+
error_exit() {
|
17
|
+
log "ERROR: $1"
|
18
|
+
exit 1
|
19
|
+
}
|
20
|
+
|
21
|
+
# Validate arguments
|
22
|
+
if [ $# -eq 0 ]; then
|
23
|
+
error_exit "Usage: $SCRIPT_NAME <feature-name> [feature-id]"
|
24
|
+
fi
|
25
|
+
|
26
|
+
FEATURE_NAME="$1"
|
27
|
+
CUSTOM_ID="${2:-}"
|
28
|
+
|
29
|
+
# Sanitize feature name
|
30
|
+
BRANCH_SAFE_NAME=$(echo "$FEATURE_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')
|
31
|
+
|
32
|
+
if [ -z "$BRANCH_SAFE_NAME" ]; then
|
33
|
+
error_exit "Invalid feature name: '$FEATURE_NAME'"
|
34
|
+
fi
|
35
|
+
|
36
|
+
# Get feature ID
|
37
|
+
if [ -n "$CUSTOM_ID" ]; then
|
38
|
+
FEATURE_ID=$(printf "%03d" "$CUSTOM_ID")
|
39
|
+
else
|
40
|
+
FEATURE_ID=$(printf "%03d" $(find "$PROJECT_ROOT/specs" -maxdepth 1 -type d -name '[0-9]*' 2>/dev/null | wc -l | awk '{print $1 + 1}'))
|
41
|
+
fi
|
42
|
+
|
43
|
+
BRANCH_NAME="${FEATURE_ID}-${BRANCH_SAFE_NAME}"
|
11
44
|
|
12
45
|
# Create directories
|
13
|
-
|
14
|
-
|
15
|
-
|
46
|
+
SPECS_DIR="$PROJECT_ROOT/specs/${BRANCH_NAME}"
|
47
|
+
PLANS_DIR="$PROJECT_ROOT/plans/${BRANCH_NAME}"
|
48
|
+
TASKS_DIR="$PROJECT_ROOT/tasks/${BRANCH_NAME}"
|
49
|
+
|
50
|
+
log "Creating feature directories for '$FEATURE_NAME'"
|
51
|
+
|
52
|
+
mkdir -p "$SPECS_DIR" || error_exit "Failed to create specs directory: $SPECS_DIR"
|
53
|
+
mkdir -p "$PLANS_DIR" || error_exit "Failed to create plans directory: $PLANS_DIR"
|
54
|
+
mkdir -p "$TASKS_DIR" || error_exit "Failed to create tasks directory: $TASKS_DIR"
|
16
55
|
|
17
56
|
# Create initial files from templates
|
18
|
-
|
19
|
-
|
20
|
-
|
57
|
+
TEMPLATE_DIR="$PROJECT_ROOT/templates"
|
58
|
+
|
59
|
+
if [ ! -f "$TEMPLATE_DIR/spec.md" ]; then
|
60
|
+
error_exit "Template not found: $TEMPLATE_DIR/spec.md"
|
61
|
+
fi
|
62
|
+
|
63
|
+
cp "$TEMPLATE_DIR/spec.md" "$SPECS_DIR/spec.md" || error_exit "Failed to copy spec template"
|
64
|
+
cp "$TEMPLATE_DIR/plan.md" "$PLANS_DIR/plan.md" || error_exit "Failed to copy plan template"
|
65
|
+
cp "$TEMPLATE_DIR/task.md" "$TASKS_DIR/tasks.md" || error_exit "Failed to copy task template"
|
21
66
|
|
22
67
|
# Update context
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
echo "
|
68
|
+
CONTEXT_FILE="$PROJECT_ROOT/memory/context.md"
|
69
|
+
mkdir -p "$(dirname "$CONTEXT_FILE")"
|
70
|
+
|
71
|
+
{
|
72
|
+
echo ""
|
73
|
+
echo "## Active Feature: $FEATURE_NAME"
|
74
|
+
echo "- Feature ID: $FEATURE_ID"
|
75
|
+
echo "- Branch: $BRANCH_NAME"
|
76
|
+
echo "- Started: $(date -Iseconds)"
|
77
|
+
} >> "$CONTEXT_FILE" || error_exit "Failed to update context file"
|
28
78
|
|
29
79
|
# Create git branch if in git repo
|
30
|
-
if [ -d
|
31
|
-
|
80
|
+
if [ -d "$PROJECT_ROOT/.git" ]; then
|
81
|
+
cd "$PROJECT_ROOT"
|
82
|
+
if git rev-parse --verify "$BRANCH_NAME" >/dev/null 2>&1; then
|
83
|
+
log "Git branch '$BRANCH_NAME' already exists, checking out"
|
84
|
+
git checkout "$BRANCH_NAME" || error_exit "Failed to checkout existing branch"
|
85
|
+
else
|
86
|
+
log "Creating new git branch '$BRANCH_NAME'"
|
87
|
+
git checkout -b "$BRANCH_NAME" || error_exit "Failed to create new branch"
|
88
|
+
fi
|
32
89
|
fi
|
33
90
|
|
34
|
-
|
35
|
-
|
36
|
-
echo "
|
91
|
+
log "Successfully initialized feature '$FEATURE_NAME' with ID $FEATURE_ID"
|
92
|
+
|
93
|
+
echo "BRANCH_NAME=$BRANCH_NAME"
|
94
|
+
echo "SPEC_DIR=$SPECS_DIR"
|
95
|
+
echo "FEATURE_ID=$FEATURE_ID"
|
37
96
|
echo "STATUS=initialized"
|