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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. specpulse/__init__.py +1 -1
  2. specpulse/cli/main.py +598 -617
  3. specpulse/core/specpulse.py +1110 -1105
  4. specpulse/resources/commands/claude/sp-continue.md +203 -0
  5. specpulse/resources/commands/claude/{plan.md → sp-plan.md} +53 -38
  6. specpulse/resources/commands/claude/sp-pulse.md +142 -0
  7. specpulse/resources/commands/claude/{spec.md → sp-spec.md} +36 -23
  8. specpulse/resources/commands/claude/sp-status.md +170 -0
  9. specpulse/resources/commands/claude/{task.md → sp-task.md} +68 -48
  10. specpulse/resources/commands/gemini/sp-continue.toml +56 -0
  11. specpulse/resources/commands/gemini/sp-plan.toml +68 -0
  12. specpulse/resources/commands/gemini/{pulse.toml → sp-pulse.toml} +12 -6
  13. specpulse/resources/commands/gemini/sp-spec.toml +54 -0
  14. specpulse/resources/commands/gemini/sp-status.toml +61 -0
  15. specpulse/resources/commands/gemini/sp-task.toml +79 -0
  16. specpulse/resources/memory/constitution.md +5 -5
  17. specpulse/resources/memory/context.md +12 -1
  18. specpulse/resources/scripts/{pulse-init.py → sp-pulse-init.py} +6 -6
  19. specpulse/resources/scripts/{pulse-init.sh → sp-pulse-init.sh} +95 -95
  20. specpulse/resources/scripts/{pulse-plan.py → sp-pulse-plan.py} +32 -7
  21. specpulse/resources/scripts/{pulse-plan.sh → sp-pulse-plan.sh} +136 -126
  22. specpulse/resources/scripts/{pulse-spec.py → sp-pulse-spec.py} +26 -6
  23. specpulse/resources/scripts/{pulse-spec.sh → sp-pulse-spec.sh} +126 -103
  24. specpulse/resources/scripts/{pulse-task.py → sp-pulse-task.py} +42 -6
  25. specpulse/resources/scripts/{pulse-task.sh → sp-pulse-task.sh} +32 -16
  26. specpulse/resources/templates/plan.md +206 -206
  27. specpulse/resources/templates/spec.md +125 -125
  28. specpulse/resources/templates/task.md +164 -163
  29. {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/METADATA +35 -35
  30. specpulse-1.1.0.dist-info/RECORD +41 -0
  31. specpulse/resources/commands/claude/pulse.md +0 -91
  32. specpulse/resources/commands/gemini/plan.toml +0 -59
  33. specpulse/resources/commands/gemini/spec.toml +0 -45
  34. specpulse/resources/commands/gemini/task.toml +0 -69
  35. specpulse/resources/scripts/pulse-init.ps1 +0 -186
  36. specpulse/resources/scripts/pulse-plan.ps1 +0 -251
  37. specpulse/resources/scripts/pulse-spec.ps1 +0 -185
  38. specpulse/resources/scripts/pulse-task.ps1 +0 -263
  39. specpulse-1.0.6.dist-info/RECORD +0 -41
  40. {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/WHEEL +0 -0
  41. {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/entry_points.txt +0 -0
  42. {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/licenses/LICENSE +0 -0
  43. {specpulse-1.0.6.dist-info → specpulse-1.1.0.dist-info}/top_level.txt +0 -0
@@ -1,127 +1,137 @@
1
- #!/bin/bash
2
- # Generate implementation plan
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-dir>"
24
- fi
25
-
26
- FEATURE_DIR="$1"
27
-
28
- # Sanitize feature directory
29
- SANITIZED_DIR=$(echo "$FEATURE_DIR" | sed 's/[^a-zA-Z0-9_-]//g')
30
-
31
- if [ -z "$SANITIZED_DIR" ]; then
32
- error_exit "Invalid feature directory: '$FEATURE_DIR'"
33
- fi
34
-
35
- # Find feature directory if not provided
36
- if [ -z "$FEATURE_DIR" ]; then
37
- CONTEXT_FILE="$PROJECT_ROOT/memory/context.md"
38
- if [ -f "$CONTEXT_FILE" ]; then
39
- FEATURE_DIR=$(grep -A1 "Active Feature" "$CONTEXT_FILE" | tail -1 | cut -d: -f2 | xargs)
40
- if [ -z "$FEATURE_DIR" ]; then
41
- error_exit "No active feature found in context file"
42
- fi
43
- log "Using active feature from context: $FEATURE_DIR"
44
- else
45
- error_exit "No feature directory provided and no context file found"
46
- fi
47
- fi
48
-
49
- PLAN_FILE="$PROJECT_ROOT/plans/${FEATURE_DIR}/plan.md"
50
- TEMPLATE_FILE="$PROJECT_ROOT/templates/plan.md"
51
- SPEC_FILE="$PROJECT_ROOT/specs/${FEATURE_DIR}/spec.md"
52
-
53
- # Ensure plans directory exists
54
- mkdir -p "$(dirname "$PLAN_FILE")"
55
-
56
- # Check if specification exists first
57
- if [ ! -f "$SPEC_FILE" ]; then
58
- error_exit "Specification file not found: $SPEC_FILE. Please create specification first."
59
- fi
60
-
61
- # Ensure plan template exists
62
- if [ ! -f "$TEMPLATE_FILE" ]; then
63
- error_exit "Template not found: $TEMPLATE_FILE"
64
- fi
65
-
66
- # Create plan if it doesn't exist
67
- if [ ! -f "$PLAN_FILE" ]; then
68
- log "Creating implementation plan from template: $PLAN_FILE"
69
- cp "$TEMPLATE_FILE" "$PLAN_FILE" || error_exit "Failed to copy plan template"
70
- else
71
- log "Implementation plan already exists: $PLAN_FILE"
72
- fi
73
-
74
- # Validate plan structure
75
- log "Validating implementation plan..."
76
-
77
- # Check for required sections
78
- REQUIRED_SECTIONS=("## Implementation Plan:" "## Specification Reference" "## Phase -1: Pre-Implementation Gates" "## Implementation Phases")
79
- MISSING_SECTIONS=()
80
-
81
- for section in "${REQUIRED_SECTIONS[@]}"; do
82
- if ! grep -q "$section" "$PLAN_FILE"; then
83
- MISSING_SECTIONS+=("$section")
84
- fi
85
- done
86
-
87
- if [ ${#MISSING_SECTIONS[@]} -gt 0 ]; then
88
- log "WARNING: Missing required sections: ${MISSING_SECTIONS[*]}"
89
- fi
90
-
91
- # Check Constitutional Gates
92
- log "Checking Constitutional Gates..."
93
-
94
- CONSTITUTIONAL_GATES=(
95
- "Simplicity Gate"
96
- "Anti-Abstraction Gate"
97
- "Test-First Gate"
98
- "Integration-First Gate"
99
- "Research Gate"
100
- )
101
-
102
- for gate in "${CONSTITUTIONAL_GATES[@]}"; do
103
- if ! grep -q "$gate" "$PLAN_FILE"; then
104
- log "WARNING: Missing constitutional gate: $gate"
105
- fi
106
- done
107
-
108
- # Check if specification has clarifications needed
109
- if grep -q "NEEDS CLARIFICATION" "$SPEC_FILE"; then
110
- CLARIFICATION_COUNT=$(grep -c "NEEDS CLARIFICATION" "$SPEC_FILE")
111
- log "WARNING: Specification has $CLARIFICATION_COUNT clarifications needed - resolve before proceeding"
112
- fi
113
-
114
- # Validate gate compliance
115
- GATE_STATUS=$(grep -A5 "Gate Status:" "$PLAN_FILE" | tail -1 | sed 's/.*\[\(.*\)\].*/\1/' || echo "PENDING")
116
-
117
- if [ "$GATE_STATUS" != "COMPLETED" ]; then
118
- log "WARNING: Constitutional gates not completed. Status: $GATE_STATUS"
119
- fi
120
-
121
- log "Implementation plan processing completed successfully"
122
-
123
- echo "PLAN_FILE=$PLAN_FILE"
124
- echo "SPEC_FILE=$SPEC_FILE"
125
- echo "MISSING_SECTIONS=${#MISSING_SECTIONS[@]}"
126
- echo "CONSTITUTIONAL_GATES_STATUS=$GATE_STATUS"
1
+ #!/bin/bash
2
+ # Generate implementation plan
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-dir>"
24
+ fi
25
+
26
+ FEATURE_DIR="$1"
27
+
28
+ # Sanitize feature directory
29
+ SANITIZED_DIR=$(echo "$FEATURE_DIR" | sed 's/[^a-zA-Z0-9_-]//g')
30
+
31
+ if [ -z "$SANITIZED_DIR" ]; then
32
+ error_exit "Invalid feature directory: '$FEATURE_DIR'"
33
+ fi
34
+
35
+ # Find feature directory if not provided
36
+ if [ -z "$FEATURE_DIR" ]; then
37
+ CONTEXT_FILE="$PROJECT_ROOT/memory/context.md"
38
+ if [ -f "$CONTEXT_FILE" ]; then
39
+ FEATURE_DIR=$(grep -A1 "Active Feature" "$CONTEXT_FILE" | tail -1 | cut -d: -f2 | xargs)
40
+ if [ -z "$FEATURE_DIR" ]; then
41
+ error_exit "No active feature found in context file"
42
+ fi
43
+ log "Using active feature from context: $FEATURE_DIR"
44
+ else
45
+ error_exit "No feature directory provided and no context file found"
46
+ fi
47
+ fi
48
+
49
+ PLAN_DIR="$PROJECT_ROOT/plans/${FEATURE_DIR}"
50
+ SPEC_DIR="$PROJECT_ROOT/specs/${FEATURE_DIR}"
51
+ TEMPLATE_FILE="$PROJECT_ROOT/templates/plan-001.md"
52
+
53
+ # Ensure plans directory exists
54
+ mkdir -p "$PLAN_DIR"
55
+
56
+ # Find latest spec file
57
+ if [ -d "$SPEC_DIR" ]; then
58
+ SPEC_FILE=$(find "$SPEC_DIR" -name "spec-*.md" -printf "%T@ %p\n" | sort -n | tail -1 | cut -d' ' -f2-)
59
+ if [ -z "$SPEC_FILE" ]; then
60
+ error_exit "No specification files found in $SPEC_DIR. Please create specification first."
61
+ fi
62
+ else
63
+ error_exit "Specifications directory not found: $SPEC_DIR. Please create specification first."
64
+ fi
65
+
66
+ # Find next available plan number or create new one
67
+ if [ -d "$PLAN_DIR" ]; then
68
+ existing_plans=$(find "$PLAN_DIR" -name "plan-*.md" | wc -l)
69
+ plan_number=$((existing_plans + 1))
70
+ else
71
+ plan_number=1
72
+ fi
73
+ PLAN_FILE="$PLAN_DIR/plan-$(printf "%03d" $plan_number).md"
74
+
75
+ # Ensure plan template exists
76
+ if [ ! -f "$TEMPLATE_FILE" ]; then
77
+ error_exit "Template not found: $TEMPLATE_FILE"
78
+ fi
79
+
80
+ # Create plan
81
+ log "Creating implementation plan from template: $PLAN_FILE"
82
+ cp "$TEMPLATE_FILE" "$PLAN_FILE" || error_exit "Failed to copy plan template"
83
+
84
+ # Validate plan structure
85
+ log "Validating implementation plan..."
86
+
87
+ # Check for required sections
88
+ REQUIRED_SECTIONS=("## Implementation Plan:" "## Specification Reference" "## Phase -1: Pre-Implementation Gates" "## Implementation Phases")
89
+ MISSING_SECTIONS=()
90
+
91
+ for section in "${REQUIRED_SECTIONS[@]}"; do
92
+ if ! grep -q "$section" "$PLAN_FILE"; then
93
+ MISSING_SECTIONS+=("$section")
94
+ fi
95
+ done
96
+
97
+ if [ ${#MISSING_SECTIONS[@]} -gt 0 ]; then
98
+ log "WARNING: Missing required sections: ${MISSING_SECTIONS[*]}"
99
+ fi
100
+
101
+ # Check Constitutional Gates
102
+ log "Checking Constitutional Gates..."
103
+
104
+ CONSTITUTIONAL_GATES=(
105
+ "Simplicity Gate"
106
+ "Anti-Abstraction Gate"
107
+ "Test-First Gate"
108
+ "Integration-First Gate"
109
+ "Research Gate"
110
+ )
111
+
112
+ for gate in "${CONSTITUTIONAL_GATES[@]}"; do
113
+ if ! grep -q "$gate" "$PLAN_FILE"; then
114
+ log "WARNING: Missing constitutional gate: $gate"
115
+ fi
116
+ done
117
+
118
+ # Check if specification has clarifications needed
119
+ if grep -q "NEEDS CLARIFICATION" "$SPEC_FILE"; then
120
+ CLARIFICATION_COUNT=$(grep -c "NEEDS CLARIFICATION" "$SPEC_FILE")
121
+ log "WARNING: Specification has $CLARIFICATION_COUNT clarifications needed - resolve before proceeding"
122
+ fi
123
+
124
+ # Validate gate compliance
125
+ GATE_STATUS=$(grep -A5 "Gate Status:" "$PLAN_FILE" | tail -1 | sed 's/.*\[\(.*\)\].*/\1/' || echo "PENDING")
126
+
127
+ if [ "$GATE_STATUS" != "COMPLETED" ]; then
128
+ log "WARNING: Constitutional gates not completed. Status: $GATE_STATUS"
129
+ fi
130
+
131
+ log "Implementation plan processing completed successfully"
132
+
133
+ echo "PLAN_FILE=$PLAN_FILE"
134
+ echo "SPEC_FILE=$SPEC_FILE"
135
+ echo "MISSING_SECTIONS=${#MISSING_SECTIONS[@]}"
136
+ echo "CONSTITUTIONAL_GATES_STATUS=$GATE_STATUS"
127
137
  echo "STATUS=ready"
@@ -13,10 +13,10 @@ import datetime
13
13
  class SpecPulseSpec:
14
14
  def __init__(self):
15
15
  self.script_name = Path(__file__).name
16
- self.project_root = Path(__file__).parent.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 / "resources" / "templates"
19
+ self.templates_dir = self.project_root / "templates"
20
20
 
21
21
  def log(self, message):
22
22
  """Log messages with timestamp"""
@@ -101,7 +101,7 @@ class SpecPulseSpec:
101
101
  def main(self, args):
102
102
  """Main execution function"""
103
103
  if len(args) < 1:
104
- self.error_exit("Usage: python pulse-spec.py <feature-dir> [spec-content]")
104
+ self.error_exit("Usage: python sp-pulse-spec.py <feature-dir> [spec-content]")
105
105
 
106
106
  feature_dir = args[0]
107
107
  spec_content = args[1] if len(args) > 1 else None
@@ -112,8 +112,24 @@ class SpecPulseSpec:
112
112
  sanitized_dir = self.get_current_feature_dir(feature_dir)
113
113
 
114
114
  # Set file paths
115
- spec_file = self.project_root / "specs" / sanitized_dir / "spec.md"
116
- template_file = self.templates_dir / "spec.md"
115
+ specs_dir = self.project_root / "specs" / sanitized_dir
116
+ spec_file = specs_dir / "spec-001.md"
117
+
118
+ # Find next available spec number
119
+ if specs_dir.exists():
120
+ existing_specs = list(specs_dir.glob("spec-*.md"))
121
+ if existing_specs:
122
+ spec_numbers = [int(f.stem.split('-')[1]) for f in existing_specs if f.stem.split('-')[1].isdigit()]
123
+ next_number = max(spec_numbers) + 1 if spec_numbers else 1
124
+ else:
125
+ next_number = 1
126
+ else:
127
+ next_number = 1
128
+ specs_dir.mkdir(parents=True, exist_ok=True)
129
+
130
+ # Update spec_file to use versioned naming
131
+ spec_file = specs_dir / f"spec-{next_number:03d}.md"
132
+ template_file = self.templates_dir / "spec-001.md"
117
133
 
118
134
  # Ensure specs directory exists
119
135
  spec_file.parent.mkdir(parents=True, exist_ok=True)
@@ -133,7 +149,11 @@ class SpecPulseSpec:
133
149
 
134
150
  self.log(f"Creating specification from template: {spec_file}")
135
151
  try:
136
- spec_file.write_text(template_file.read_text(encoding='utf-8'))
152
+ template_content = template_file.read_text(encoding='utf-8')
153
+ # Update template content to use sp- prefixed commands
154
+ template_content = template_content.replace("/plan ", "/sp-plan ")
155
+ template_content = template_content.replace("/task ", "/sp-task ")
156
+ spec_file.write_text(template_content)
137
157
  except Exception as e:
138
158
  self.error_exit(f"Failed to copy specification template: {e}")
139
159
  else:
@@ -1,104 +1,127 @@
1
- #!/bin/bash
2
- # Generate or update specification
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-dir> [spec-content]"
24
- fi
25
-
26
- FEATURE_DIR="$1"
27
- SPEC_CONTENT="${2:-}"
28
-
29
- # Sanitize feature directory
30
- SANITIZED_DIR=$(echo "$FEATURE_DIR" | sed 's/[^a-zA-Z0-9_-]//g')
31
-
32
- if [ -z "$SANITIZED_DIR" ]; then
33
- error_exit "Invalid feature directory: '$FEATURE_DIR'"
34
- fi
35
-
36
- # Find feature directory if not provided
37
- if [ -z "$FEATURE_DIR" ]; then
38
- CONTEXT_FILE="$PROJECT_ROOT/memory/context.md"
39
- if [ -f "$CONTEXT_FILE" ]; then
40
- FEATURE_DIR=$(grep -A1 "Active Feature" "$CONTEXT_FILE" | tail -1 | cut -d: -f2 | xargs)
41
- if [ -z "$FEATURE_DIR" ]; then
42
- error_exit "No active feature found in context file"
43
- fi
44
- log "Using active feature from context: $FEATURE_DIR"
45
- else
46
- error_exit "No feature directory provided and no context file found"
47
- fi
48
- fi
49
-
50
- SPEC_FILE="$PROJECT_ROOT/specs/${FEATURE_DIR}/spec.md"
51
- TEMPLATE_FILE="$PROJECT_ROOT/templates/spec.md"
52
-
53
- # Ensure specs directory exists
54
- mkdir -p "$(dirname "$SPEC_FILE")"
55
-
56
- if [ -n "$SPEC_CONTENT" ]; then
57
- # Update specification with provided content
58
- log "Updating specification: $SPEC_FILE"
59
- echo "$SPEC_CONTENT" > "$SPEC_FILE" || error_exit "Failed to write specification content"
60
- else
61
- # Ensure specification exists from template
62
- if [ ! -f "$SPEC_FILE" ]; then
63
- if [ ! -f "$TEMPLATE_FILE" ]; then
64
- error_exit "Template not found: $TEMPLATE_FILE"
65
- fi
66
- log "Creating specification from template: $SPEC_FILE"
67
- cp "$TEMPLATE_FILE" "$SPEC_FILE" || error_exit "Failed to copy specification template"
68
- else
69
- log "Specification already exists: $SPEC_FILE"
70
- fi
71
- fi
72
-
73
- # Validate specification
74
- log "Validating specification..."
75
- if [ ! -f "$SPEC_FILE" ]; then
76
- error_exit "Specification file does not exist: $SPEC_FILE"
77
- fi
78
-
79
- # Check for required sections
80
- REQUIRED_SECTIONS=("## Specification:" "## Metadata" "## Functional Requirements" "## Acceptance Scenarios")
81
- MISSING_SECTIONS=()
82
-
83
- for section in "${REQUIRED_SECTIONS[@]}"; do
84
- if ! grep -q "$section" "$SPEC_FILE"; then
85
- MISSING_SECTIONS+=("$section")
86
- fi
87
- done
88
-
89
- if [ ${#MISSING_SECTIONS[@]} -gt 0 ]; then
90
- log "WARNING: Missing required sections: ${MISSING_SECTIONS[*]}"
91
- fi
92
-
93
- # Check for clarifications needed
94
- if grep -q "NEEDS CLARIFICATION" "$SPEC_FILE"; then
95
- CLARIFICATION_COUNT=$(grep -c "NEEDS CLARIFICATION" "$SPEC_FILE")
96
- log "WARNING: Specification has $CLARIFICATION_COUNT clarifications needed"
97
- fi
98
-
99
- log "Specification processing completed successfully"
100
-
101
- echo "SPEC_FILE=$SPEC_FILE"
102
- echo "CLARIFICATIONS_NEEDED=${CLARIFICATION_COUNT:-0}"
103
- echo "MISSING_SECTIONS=${#MISSING_SECTIONS[@]}"
1
+ #!/bin/bash
2
+ # Generate or update specification
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-dir> [spec-content]"
24
+ fi
25
+
26
+ FEATURE_DIR="$1"
27
+ SPEC_CONTENT="${2:-}"
28
+
29
+ # Sanitize feature directory
30
+ SANITIZED_DIR=$(echo "$FEATURE_DIR" | sed 's/[^a-zA-Z0-9_-]//g')
31
+
32
+ if [ -z "$SANITIZED_DIR" ]; then
33
+ error_exit "Invalid feature directory: '$FEATURE_DIR'"
34
+ fi
35
+
36
+ # Find feature directory if not provided
37
+ if [ -z "$FEATURE_DIR" ]; then
38
+ CONTEXT_FILE="$PROJECT_ROOT/memory/context.md"
39
+ if [ -f "$CONTEXT_FILE" ]; then
40
+ FEATURE_DIR=$(grep -A1 "Active Feature" "$CONTEXT_FILE" | tail -1 | cut -d: -f2 | xargs)
41
+ if [ -z "$FEATURE_DIR" ]; then
42
+ error_exit "No active feature found in context file"
43
+ fi
44
+ log "Using active feature from context: $FEATURE_DIR"
45
+ else
46
+ error_exit "No feature directory provided and no context file found"
47
+ fi
48
+ fi
49
+
50
+ SPEC_DIR="$PROJECT_ROOT/specs/${FEATURE_DIR}"
51
+ TEMPLATE_FILE="$PROJECT_ROOT/templates/spec-001.md"
52
+
53
+ # Ensure specs directory exists
54
+ mkdir -p "$SPEC_DIR"
55
+
56
+ # Find latest spec file or create new one
57
+ if [ -n "$SPEC_CONTENT" ]; then
58
+ # Find next available spec number
59
+ if [ -d "$SPEC_DIR" ]; then
60
+ existing_specs=$(find "$SPEC_DIR" -name "spec-*.md" | wc -l)
61
+ spec_number=$((existing_specs + 1))
62
+ else
63
+ spec_number=1
64
+ fi
65
+ SPEC_FILE="$SPEC_DIR/spec-$(printf "%03d" $spec_number).md"
66
+
67
+ # Update specification with provided content
68
+ log "Creating specification: $SPEC_FILE"
69
+ echo "$SPEC_CONTENT" > "$SPEC_FILE" || error_exit "Failed to write specification content"
70
+ else
71
+ # Find latest spec file
72
+ if [ -d "$SPEC_DIR" ]; then
73
+ SPEC_FILE=$(find "$SPEC_DIR" -name "spec-*.md" -printf "%T@ %p\n" | sort -n | tail -1 | cut -d' ' -f2-)
74
+ if [ -z "$SPEC_FILE" ]; then
75
+ # No spec files found, create first one
76
+ SPEC_FILE="$SPEC_DIR/spec-001.md"
77
+ if [ ! -f "$TEMPLATE_FILE" ]; then
78
+ error_exit "Template not found: $TEMPLATE_FILE"
79
+ fi
80
+ log "Creating specification from template: $SPEC_FILE"
81
+ cp "$TEMPLATE_FILE" "$SPEC_FILE" || error_exit "Failed to copy specification template"
82
+ else
83
+ log "Using latest specification: $SPEC_FILE"
84
+ fi
85
+ else
86
+ # Create directory and first spec
87
+ SPEC_FILE="$SPEC_DIR/spec-001.md"
88
+ if [ ! -f "$TEMPLATE_FILE" ]; then
89
+ error_exit "Template not found: $TEMPLATE_FILE"
90
+ fi
91
+ log "Creating specification from template: $SPEC_FILE"
92
+ cp "$TEMPLATE_FILE" "$SPEC_FILE" || error_exit "Failed to copy specification template"
93
+ fi
94
+ fi
95
+
96
+ # Validate specification
97
+ log "Validating specification..."
98
+ if [ ! -f "$SPEC_FILE" ]; then
99
+ error_exit "Specification file does not exist: $SPEC_FILE"
100
+ fi
101
+
102
+ # Check for required sections
103
+ REQUIRED_SECTIONS=("## Specification:" "## Metadata" "## Functional Requirements" "## Acceptance Scenarios")
104
+ MISSING_SECTIONS=()
105
+
106
+ for section in "${REQUIRED_SECTIONS[@]}"; do
107
+ if ! grep -q "$section" "$SPEC_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[*]}"
114
+ fi
115
+
116
+ # Check for clarifications needed
117
+ if grep -q "NEEDS CLARIFICATION" "$SPEC_FILE"; then
118
+ CLARIFICATION_COUNT=$(grep -c "NEEDS CLARIFICATION" "$SPEC_FILE")
119
+ log "WARNING: Specification has $CLARIFICATION_COUNT clarifications needed"
120
+ fi
121
+
122
+ log "Specification processing completed successfully"
123
+
124
+ echo "SPEC_FILE=$SPEC_FILE"
125
+ echo "CLARIFICATIONS_NEEDED=${CLARIFICATION_COUNT:-0}"
126
+ echo "MISSING_SECTIONS=${#MISSING_SECTIONS[@]}"
104
127
  echo "STATUS=updated"
@@ -13,10 +13,10 @@ import datetime
13
13
  class SpecPulseTask:
14
14
  def __init__(self):
15
15
  self.script_name = Path(__file__).name
16
- self.project_root = Path(__file__).parent.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 / "resources" / "templates"
19
+ self.templates_dir = self.project_root / "templates"
20
20
 
21
21
  def log(self, message):
22
22
  """Log messages with timestamp"""
@@ -155,7 +155,7 @@ class SpecPulseTask:
155
155
  def main(self, args):
156
156
  """Main execution function"""
157
157
  if len(args) < 1:
158
- self.error_exit("Usage: python pulse-task.py <feature-dir>")
158
+ self.error_exit("Usage: python sp-pulse-task.py <feature-dir>")
159
159
 
160
160
  feature_dir = args[0]
161
161
 
@@ -165,10 +165,46 @@ class SpecPulseTask:
165
165
  sanitized_dir = self.get_current_feature_dir(feature_dir)
166
166
 
167
167
  # Set file paths
168
- task_file = self.project_root / "tasks" / sanitized_dir / "tasks.md"
168
+ plans_dir = self.project_root / "plans" / sanitized_dir
169
+ tasks_dir = self.project_root / "tasks" / sanitized_dir
170
+
171
+ # Find latest spec and plan files
172
+ specs_dir = self.project_root / "specs" / sanitized_dir
173
+
174
+ if specs_dir.exists():
175
+ spec_files = list(specs_dir.glob("spec-*.md"))
176
+ if spec_files:
177
+ latest_spec = max(spec_files, key=lambda f: f.stat().st_mtime)
178
+ else:
179
+ self.error_exit(f"No spec files found in {specs_dir}")
180
+ else:
181
+ self.error_exit(f"Specs directory not found: {specs_dir}")
182
+
183
+ if plans_dir.exists():
184
+ plan_files = list(plans_dir.glob("plan-*.md"))
185
+ if plan_files:
186
+ latest_plan = max(plan_files, key=lambda f: f.stat().st_mtime)
187
+ else:
188
+ self.error_exit(f"No plan files found in {plans_dir}")
189
+ else:
190
+ self.error_exit(f"Plans directory not found: {plans_dir}")
191
+
192
+ # Find next available task number
193
+ if tasks_dir.exists():
194
+ existing_tasks = list(tasks_dir.glob("task-*.md"))
195
+ if existing_tasks:
196
+ task_numbers = [int(f.stem.split('-')[1]) for f in existing_tasks if f.stem.split('-')[1].isdigit()]
197
+ next_number = max(task_numbers) + 1 if task_numbers else 1
198
+ else:
199
+ next_number = 1
200
+ else:
201
+ next_number = 1
202
+ tasks_dir.mkdir(parents=True, exist_ok=True)
203
+
204
+ task_file = tasks_dir / f"task-{next_number:03d}.md"
169
205
  template_file = self.templates_dir / "task.md"
170
- plan_file = self.project_root / "plans" / sanitized_dir / "plan.md"
171
- spec_file = self.project_root / "specs" / sanitized_dir / "spec.md"
206
+ plan_file = latest_plan
207
+ spec_file = latest_spec
172
208
 
173
209
  # Ensure tasks directory exists
174
210
  task_file.parent.mkdir(parents=True, exist_ok=True)