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.
- specpulse/__init__.py +1 -1
- specpulse/cli/main.py +598 -617
- specpulse/core/specpulse.py +1110 -1105
- specpulse/resources/commands/claude/sp-continue.md +203 -0
- specpulse/resources/commands/claude/{plan.md → sp-plan.md} +53 -38
- specpulse/resources/commands/claude/sp-pulse.md +142 -0
- specpulse/resources/commands/claude/{spec.md → sp-spec.md} +36 -23
- specpulse/resources/commands/claude/sp-status.md +170 -0
- specpulse/resources/commands/claude/{task.md → sp-task.md} +68 -48
- specpulse/resources/commands/gemini/sp-continue.toml +56 -0
- specpulse/resources/commands/gemini/sp-plan.toml +68 -0
- specpulse/resources/commands/gemini/{pulse.toml → sp-pulse.toml} +12 -6
- specpulse/resources/commands/gemini/sp-spec.toml +54 -0
- specpulse/resources/commands/gemini/sp-status.toml +61 -0
- specpulse/resources/commands/gemini/sp-task.toml +79 -0
- specpulse/resources/memory/constitution.md +5 -5
- specpulse/resources/memory/context.md +12 -1
- specpulse/resources/scripts/{pulse-init.py → sp-pulse-init.py} +6 -6
- specpulse/resources/scripts/{pulse-init.sh → sp-pulse-init.sh} +95 -95
- specpulse/resources/scripts/{pulse-plan.py → sp-pulse-plan.py} +32 -7
- specpulse/resources/scripts/{pulse-plan.sh → sp-pulse-plan.sh} +136 -126
- specpulse/resources/scripts/{pulse-spec.py → sp-pulse-spec.py} +26 -6
- specpulse/resources/scripts/{pulse-spec.sh → sp-pulse-spec.sh} +126 -103
- specpulse/resources/scripts/{pulse-task.py → sp-pulse-task.py} +42 -6
- specpulse/resources/scripts/{pulse-task.sh → sp-pulse-task.sh} +32 -16
- specpulse/resources/templates/plan.md +206 -206
- specpulse/resources/templates/spec.md +125 -125
- specpulse/resources/templates/task.md +164 -163
- {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/METADATA +35 -35
- specpulse-1.1.0.dist-info/RECORD +41 -0
- specpulse/resources/commands/claude/pulse.md +0 -91
- specpulse/resources/commands/gemini/plan.toml +0 -59
- specpulse/resources/commands/gemini/spec.toml +0 -45
- specpulse/resources/commands/gemini/task.toml +0 -69
- specpulse/resources/scripts/pulse-init.ps1 +0 -186
- specpulse/resources/scripts/pulse-plan.ps1 +0 -251
- specpulse/resources/scripts/pulse-spec.ps1 +0 -185
- specpulse/resources/scripts/pulse-task.ps1 +0 -263
- specpulse-1.0.6.dist-info/RECORD +0 -41
- {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/WHEEL +0 -0
- {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/entry_points.txt +0 -0
- {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
description = "Track progress across all features or specific feature details"
|
2
|
+
prompt = """
|
3
|
+
Handle the /sp-status command with arguments: {{args}}
|
4
|
+
|
5
|
+
First, detect current feature context:
|
6
|
+
- Read memory/context.md for current feature metadata
|
7
|
+
- Use git branch name if available (e.g., 001-user-authentication)
|
8
|
+
- Fall back to most recently created feature directory
|
9
|
+
- If no context found, work with all features
|
10
|
+
|
11
|
+
Parse arguments to determine scope:
|
12
|
+
- If feature name provided: Show detailed status for that feature
|
13
|
+
- Otherwise: Show overview of all features
|
14
|
+
|
15
|
+
## For /sp-status (all features overview):
|
16
|
+
1. Scan all feature directories (specs/*, plans/*, tasks/*)
|
17
|
+
2. Count features by status: active, completed, in_progress, paused
|
18
|
+
3. Calculate overall project progress
|
19
|
+
4. Show summary statistics:
|
20
|
+
```
|
21
|
+
TOTAL_FEATURES=5
|
22
|
+
ACTIVE_FEATURES=2
|
23
|
+
COMPLETED_FEATURES=1
|
24
|
+
IN_PROGRESS_FEATURES=1
|
25
|
+
PAUSED_FEATURES=1
|
26
|
+
OVERALL_PROGRESS=42%
|
27
|
+
```
|
28
|
+
5. List all features with their status and progress percentage
|
29
|
+
6. Highlight current active feature from context
|
30
|
+
|
31
|
+
## For /sp-status [feature-name] (detailed feature status):
|
32
|
+
1. Detect feature directory using context detection logic
|
33
|
+
2. Read all task files in the feature's tasks directory
|
34
|
+
3. Calculate completion percentage based on task status
|
35
|
+
4. Show detailed breakdown:
|
36
|
+
```
|
37
|
+
FEATURE: 001-user-authentication
|
38
|
+
STATUS: active
|
39
|
+
PROGRESS: 65%
|
40
|
+
SPECS: 2 files
|
41
|
+
PLANS: 1 file
|
42
|
+
TASKS: 1 file (25 total tasks)
|
43
|
+
COMPLETED_TASKS: 16
|
44
|
+
IN_PROGRESS_TASKS: 5
|
45
|
+
BLOCKED_TASKS: 1
|
46
|
+
LAST_UPDATED: 2025-01-09
|
47
|
+
```
|
48
|
+
5. Show phase-by-phase progress
|
49
|
+
6. List any blockers or issues
|
50
|
+
7. Provide recommendations for next steps
|
51
|
+
|
52
|
+
Progress calculation:
|
53
|
+
- Scan task files for completion status: [x] completed, [ ] pending, [-] in progress, [!] blocked
|
54
|
+
- Calculate percentages: completed / total * 100
|
55
|
+
- Track status: active, completed, in_progress, paused, blocked
|
56
|
+
|
57
|
+
Examples:
|
58
|
+
- /sp-status
|
59
|
+
- /sp-status user-authentication
|
60
|
+
- /sp-status 001
|
61
|
+
"""
|
@@ -0,0 +1,79 @@
|
|
1
|
+
description = "Generate and manage task breakdowns with versioning"
|
2
|
+
prompt = """
|
3
|
+
Handle the /sp-task command with arguments: {{args}}
|
4
|
+
|
5
|
+
First, detect current feature context:
|
6
|
+
- Read memory/context.md for current feature metadata
|
7
|
+
- Use git branch name if available (e.g., 001-user-authentication)
|
8
|
+
- Fall back to most recently created feature directory
|
9
|
+
- If no context found, ask user to specify feature or run /sp-pulse first
|
10
|
+
|
11
|
+
Parse arguments to determine action:
|
12
|
+
- If "update": Update task status
|
13
|
+
- If "status": Show progress
|
14
|
+
- Otherwise: Generate task breakdown
|
15
|
+
|
16
|
+
## For /sp-task breakdown or /sp-task:
|
17
|
+
1. Show list of existing plan files in current feature directory
|
18
|
+
2. Ask user which plan file to base tasks on
|
19
|
+
3. Read selected implementation plan from @{plans/*/plan-XXX.md}
|
20
|
+
|
21
|
+
4. Generate tasks from plan:
|
22
|
+
- Create task categories:
|
23
|
+
• Critical Path (Phase 0)
|
24
|
+
• Phase 1: Foundation
|
25
|
+
• Phase 2: Core Features
|
26
|
+
• Phase 3: Polish
|
27
|
+
• Phase 4: Testing
|
28
|
+
|
29
|
+
- For each task:
|
30
|
+
• Use T[XXX] format (T001, T002)
|
31
|
+
• Include clear description
|
32
|
+
• Mark dependencies
|
33
|
+
• Estimate complexity (S/M/L/XL)
|
34
|
+
• Assign priority
|
35
|
+
|
36
|
+
5. Check existing task files and create next version (task-001.md, task-002.md, etc.)
|
37
|
+
6. Write tasks to tasks/XXX-feature/task-XXX.md
|
38
|
+
7. Run cross-platform validation:
|
39
|
+
- Linux/macOS: !{bash scripts/sp-pulse-task.sh "XXX-feature"}
|
40
|
+
- Fallback: !{python scripts/sp-pulse-task.py "XXX-feature"}
|
41
|
+
|
42
|
+
## For /sp-task update:
|
43
|
+
1. Show list of existing task files in current feature directory
|
44
|
+
2. Ask user which task file to update
|
45
|
+
3. Read selected current tasks from @{tasks/*/task-XXX.md}
|
46
|
+
4. Ask which tasks to update
|
47
|
+
5. Mark tasks as completed/in-progress
|
48
|
+
6. Add newly discovered tasks
|
49
|
+
7. Update dependencies and blockers
|
50
|
+
8. Save updated task list
|
51
|
+
9. Run cross-platform validation:
|
52
|
+
- Linux/macOS: !{bash scripts/sp-pulse-task.sh "XXX-feature"}
|
53
|
+
- Fallback: !{python scripts/sp-pulse-task.py "XXX-feature"}
|
54
|
+
|
55
|
+
## For /sp-task status:
|
56
|
+
1. Show list of existing task files in current feature directory
|
57
|
+
2. Ask user which task file to show status for
|
58
|
+
3. Read selected current tasks
|
59
|
+
4. Run cross-platform analysis:
|
60
|
+
- Linux/macOS: !{bash scripts/sp-pulse-task.sh "XXX-feature"}
|
61
|
+
- Fallback: !{python scripts/sp-pulse-task.py "XXX-feature"}
|
62
|
+
5. Count completed vs total
|
63
|
+
6. Show current phase progress
|
64
|
+
7. List any blockers
|
65
|
+
8. Estimate remaining work
|
66
|
+
9. Display progress summary
|
67
|
+
|
68
|
+
Task Format:
|
69
|
+
```markdown
|
70
|
+
- [ ] T001: [S] Set up project structure
|
71
|
+
- [ ] T002: [M] Create database schema
|
72
|
+
- [x] T003: [L] Implement authentication
|
73
|
+
```
|
74
|
+
|
75
|
+
Examples:
|
76
|
+
- /sp-task breakdown
|
77
|
+
- /sp-task update
|
78
|
+
- /sp-task status
|
79
|
+
"""
|
@@ -110,7 +110,7 @@ This includes:
|
|
110
110
|
Every implementation plan MUST pass through constitutional gates:
|
111
111
|
|
112
112
|
#### Phase -1: Pre-Implementation Gates
|
113
|
-
- [ ] Simplicity Gate (Article VII): Using
|
113
|
+
- [ ] Simplicity Gate (Article VII): Using <=3 projects? No future-proofing?
|
114
114
|
- [ ] Anti-Abstraction Gate (Article VII): Using framework directly? Single model?
|
115
115
|
- [ ] Test-First Gate (Article III): Tests written? Tests reviewed? Tests failing?
|
116
116
|
- [ ] Integration-First Gate (Article VIII): Contracts defined? Contract tests written?
|
@@ -188,11 +188,11 @@ While principles are immutable, their application can evolve:
|
|
188
188
|
|
189
189
|
### SpecPulse Development Process
|
190
190
|
1. `specpulse init` - Initialize feature with proper structure
|
191
|
-
2. Create specification following template guidelines
|
192
|
-
3. Generate implementation plan with Phase Gates
|
193
|
-
4. Break down into executable tasks
|
191
|
+
2. `/sp-spec` - Create specification following template guidelines
|
192
|
+
3. `/sp-plan` - Generate implementation plan with Phase Gates
|
193
|
+
4. `/sp-task` - Break down into executable tasks
|
194
194
|
5. Execute with Test-First Development
|
195
|
-
6. Validate against constitution and specification
|
195
|
+
6. `/sp-validate` - Validate against constitution and specification
|
196
196
|
7. Update specifications based on learnings
|
197
197
|
|
198
198
|
### Version Control
|
@@ -24,4 +24,15 @@
|
|
24
24
|
<!-- Key performance indicators -->
|
25
25
|
|
26
26
|
## Team Notes
|
27
|
-
<!-- Important reminders or observations -->
|
27
|
+
<!-- Important reminders or observations -->
|
28
|
+
|
29
|
+
## Active Feature: test-feature
|
30
|
+
- Feature ID: 001
|
31
|
+
- Branch: 001-test-feature
|
32
|
+
- Started: 2025-09-12T00:06:47.683447
|
33
|
+
|
34
|
+
|
35
|
+
## Active Feature: test-feature-2
|
36
|
+
- Feature ID: 001
|
37
|
+
- Branch: 001-test-feature-2
|
38
|
+
- Started: 2025-09-12T00:09:08.283919
|
@@ -14,10 +14,10 @@ from pathlib import Path
|
|
14
14
|
class SpecPulseInit:
|
15
15
|
def __init__(self):
|
16
16
|
self.script_name = Path(__file__).name
|
17
|
-
self.project_root = Path(__file__).parent.parent
|
17
|
+
self.project_root = Path(__file__).parent.parent
|
18
18
|
self.memory_dir = self.project_root / "memory"
|
19
19
|
self.context_file = self.memory_dir / "context.md"
|
20
|
-
self.templates_dir = self.project_root / "
|
20
|
+
self.templates_dir = self.project_root / "templates"
|
21
21
|
|
22
22
|
def log(self, message):
|
23
23
|
"""Log messages with timestamp"""
|
@@ -77,9 +77,9 @@ class SpecPulseInit:
|
|
77
77
|
def copy_templates(self, branch_name):
|
78
78
|
"""Copy templates to feature directories"""
|
79
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 / "
|
80
|
+
"spec.md": self.project_root / "specs" / branch_name / "spec-001.md",
|
81
|
+
"plan.md": self.project_root / "plans" / branch_name / "plan-001.md",
|
82
|
+
"task.md": self.project_root / "tasks" / branch_name / "task-001.md"
|
83
83
|
}
|
84
84
|
|
85
85
|
for template_name, target_path in templates.items():
|
@@ -140,7 +140,7 @@ class SpecPulseInit:
|
|
140
140
|
def main(self, args):
|
141
141
|
"""Main execution function"""
|
142
142
|
if len(args) < 1:
|
143
|
-
self.error_exit("Usage: python pulse-init.py <feature-name> [feature-id]")
|
143
|
+
self.error_exit("Usage: python sp-pulse-init.py <feature-name> [feature-id]")
|
144
144
|
|
145
145
|
feature_name = args[0]
|
146
146
|
custom_id = args[1] if len(args) > 1 else None
|
@@ -1,96 +1,96 @@
|
|
1
|
-
#!/bin/bash
|
2
|
-
# Initialize a new feature with SpecPulse
|
3
|
-
|
4
|
-
set -euo pipefail # Exit on error, unset vars, pipe failures
|
5
|
-
|
6
|
-
# Configuration
|
7
|
-
SCRIPT_NAME="$(basename "$0")"
|
8
|
-
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
9
|
-
|
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}"
|
44
|
-
|
45
|
-
# Create directories
|
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"
|
55
|
-
|
56
|
-
# Create initial files from templates
|
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/
|
66
|
-
|
67
|
-
# Update context
|
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"
|
78
|
-
|
79
|
-
# Create git branch if in git repo
|
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
|
89
|
-
fi
|
90
|
-
|
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"
|
1
|
+
#!/bin/bash
|
2
|
+
# Initialize a new feature with SpecPulse
|
3
|
+
|
4
|
+
set -euo pipefail # Exit on error, unset vars, pipe failures
|
5
|
+
|
6
|
+
# Configuration
|
7
|
+
SCRIPT_NAME="$(basename "$0")"
|
8
|
+
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
9
|
+
|
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}"
|
44
|
+
|
45
|
+
# Create directories
|
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"
|
55
|
+
|
56
|
+
# Create initial files from templates
|
57
|
+
TEMPLATE_DIR="$PROJECT_ROOT/templates"
|
58
|
+
|
59
|
+
if [ ! -f "$TEMPLATE_DIR/spec-001.md" ]; then
|
60
|
+
error_exit "Template not found: $TEMPLATE_DIR/spec-001.md"
|
61
|
+
fi
|
62
|
+
|
63
|
+
cp "$TEMPLATE_DIR/spec-001.md" "$SPECS_DIR/spec-001.md" || error_exit "Failed to copy spec template"
|
64
|
+
cp "$TEMPLATE_DIR/plan-001.md" "$PLANS_DIR/plan-001.md" || error_exit "Failed to copy plan template"
|
65
|
+
cp "$TEMPLATE_DIR/task.md" "$TASKS_DIR/task-001.md" || error_exit "Failed to copy task template"
|
66
|
+
|
67
|
+
# Update context
|
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"
|
78
|
+
|
79
|
+
# Create git branch if in git repo
|
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
|
89
|
+
fi
|
90
|
+
|
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"
|
96
96
|
echo "STATUS=initialized"
|
@@ -13,10 +13,10 @@ import datetime
|
|
13
13
|
class SpecPulsePlan:
|
14
14
|
def __init__(self):
|
15
15
|
self.script_name = Path(__file__).name
|
16
|
-
self.project_root = Path(__file__).parent.parent
|
16
|
+
self.project_root = Path(__file__).parent.parent
|
17
17
|
self.memory_dir = self.project_root / "memory"
|
18
18
|
self.context_file = self.memory_dir / "context.md"
|
19
|
-
self.templates_dir = self.project_root / "
|
19
|
+
self.templates_dir = self.project_root / "templates"
|
20
20
|
|
21
21
|
def log(self, message):
|
22
22
|
"""Log messages with timestamp"""
|
@@ -126,7 +126,7 @@ class SpecPulsePlan:
|
|
126
126
|
def main(self, args):
|
127
127
|
"""Main execution function"""
|
128
128
|
if len(args) < 1:
|
129
|
-
self.error_exit("Usage: python pulse-plan.py <feature-dir>")
|
129
|
+
self.error_exit("Usage: python sp-pulse-plan.py <feature-dir>")
|
130
130
|
|
131
131
|
feature_dir = args[0]
|
132
132
|
|
@@ -136,9 +136,34 @@ class SpecPulsePlan:
|
|
136
136
|
sanitized_dir = self.get_current_feature_dir(feature_dir)
|
137
137
|
|
138
138
|
# Set file paths
|
139
|
-
|
140
|
-
|
141
|
-
|
139
|
+
specs_dir = self.project_root / "specs" / sanitized_dir
|
140
|
+
plans_dir = self.project_root / "plans" / sanitized_dir
|
141
|
+
|
142
|
+
# Find latest spec file
|
143
|
+
if specs_dir.exists():
|
144
|
+
spec_files = list(specs_dir.glob("spec-*.md"))
|
145
|
+
if spec_files:
|
146
|
+
latest_spec = max(spec_files, key=lambda f: f.stat().st_mtime)
|
147
|
+
else:
|
148
|
+
self.error_exit(f"No specification files found in {specs_dir}")
|
149
|
+
else:
|
150
|
+
self.error_exit(f"Specifications directory not found: {specs_dir}")
|
151
|
+
|
152
|
+
# Find next available plan number
|
153
|
+
if plans_dir.exists():
|
154
|
+
existing_plans = list(plans_dir.glob("plan-*.md"))
|
155
|
+
if existing_plans:
|
156
|
+
plan_numbers = [int(f.stem.split('-')[1]) for f in existing_plans if f.stem.split('-')[1].isdigit()]
|
157
|
+
next_number = max(plan_numbers) + 1 if plan_numbers else 1
|
158
|
+
else:
|
159
|
+
next_number = 1
|
160
|
+
else:
|
161
|
+
next_number = 1
|
162
|
+
plans_dir.mkdir(parents=True, exist_ok=True)
|
163
|
+
|
164
|
+
plan_file = plans_dir / f"plan-{next_number:03d}.md"
|
165
|
+
template_file = self.templates_dir / "plan-001.md"
|
166
|
+
spec_file = latest_spec
|
142
167
|
|
143
168
|
# Ensure plans directory exists
|
144
169
|
plan_file.parent.mkdir(parents=True, exist_ok=True)
|
@@ -155,7 +180,7 @@ class SpecPulsePlan:
|
|
155
180
|
if not plan_file.exists():
|
156
181
|
self.log(f"Creating implementation plan from template: {plan_file}")
|
157
182
|
try:
|
158
|
-
plan_file.write_text(template_file.read_text(encoding='utf-8'))
|
183
|
+
plan_file.write_text(template_file.read_text(encoding='utf-8'), encoding='utf-8')
|
159
184
|
except Exception as e:
|
160
185
|
self.error_exit(f"Failed to copy plan template: {e}")
|
161
186
|
else:
|