specpulse 1.4.0__py3-none-any.whl → 1.4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. specpulse/__init__.py +1 -1
  2. specpulse/cli/main.py +30 -8
  3. specpulse/core/specpulse.py +328 -3
  4. specpulse/core/validator.py +115 -5
  5. specpulse/resources/commands/gemini/sp-pulse.toml +80 -23
  6. specpulse/resources/commands/gemini/sp-spec.toml +90 -45
  7. specpulse/resources/scripts/sp-pulse-decompose.ps1 +74 -0
  8. specpulse/resources/scripts/sp-pulse-execute.ps1 +177 -0
  9. specpulse/resources/scripts/sp-pulse-init.ps1 +36 -11
  10. specpulse/resources/scripts/sp-pulse-init.sh +29 -8
  11. specpulse/resources/scripts/sp-pulse-plan.sh +42 -17
  12. specpulse/resources/scripts/sp-pulse-spec.sh +49 -25
  13. specpulse/resources/scripts/sp-pulse-task.sh +49 -17
  14. specpulse/resources/templates/decomposition/api-contract.yaml +344 -12
  15. specpulse/resources/templates/decomposition/integration-plan.md +249 -97
  16. specpulse/resources/templates/decomposition/interface.ts +244 -13
  17. specpulse/resources/templates/decomposition/microservice.md +151 -0
  18. specpulse/resources/templates/decomposition/service-plan.md +187 -155
  19. specpulse/resources/templates/plan.md +134 -225
  20. specpulse/resources/templates/spec.md +94 -125
  21. specpulse/resources/templates/task.md +216 -161
  22. specpulse/utils/console.py +54 -6
  23. specpulse/utils/git_utils.py +47 -4
  24. specpulse/utils/version_check.py +15 -2
  25. {specpulse-1.4.0.dist-info → specpulse-1.4.2.dist-info}/METADATA +36 -17
  26. {specpulse-1.4.0.dist-info → specpulse-1.4.2.dist-info}/RECORD +30 -28
  27. specpulse/resources/templates/decomposition/microservices.md +0 -35
  28. {specpulse-1.4.0.dist-info → specpulse-1.4.2.dist-info}/WHEEL +0 -0
  29. {specpulse-1.4.0.dist-info → specpulse-1.4.2.dist-info}/entry_points.txt +0 -0
  30. {specpulse-1.4.0.dist-info → specpulse-1.4.2.dist-info}/licenses/LICENSE +0 -0
  31. {specpulse-1.4.0.dist-info → specpulse-1.4.2.dist-info}/top_level.txt +0 -0
@@ -41,15 +41,25 @@ fi
41
41
  SPEC_DIR="$PROJECT_ROOT/specs/${FEATURE_DIR}"
42
42
  TEMPLATE_FILE="$PROJECT_ROOT/templates/spec.md"
43
43
 
44
+ # Validate template file exists before proceeding
45
+ if [ ! -f "$TEMPLATE_FILE" ]; then
46
+ error_exit "Template not found: $TEMPLATE_FILE. Please ensure templates are properly initialized."
47
+ fi
48
+
44
49
  # Ensure specs directory exists
45
- mkdir -p "$SPEC_DIR"
50
+ mkdir -p "$SPEC_DIR" || error_exit "Failed to create specs directory: $SPEC_DIR"
46
51
 
47
52
  # Find latest spec file or create new one
48
53
  if [ -n "$SPEC_CONTENT" ]; then
49
54
  # Find next available spec number
50
55
  if [ -d "$SPEC_DIR" ]; then
51
- existing_specs=$(find "$SPEC_DIR" -name "spec-*.md" | wc -l)
52
- spec_number=$((existing_specs + 1))
56
+ # Get the highest spec number and increment it
57
+ highest_spec=$(find "$SPEC_DIR" -name "spec-*.md" -exec basename {} .md \; | sed 's/spec-//' | sort -n | tail -1)
58
+ if [ -n "$highest_spec" ]; then
59
+ spec_number=$((highest_spec + 1))
60
+ else
61
+ spec_number=1
62
+ fi
53
63
  else
54
64
  spec_number=1
55
65
  fi
@@ -63,24 +73,32 @@ else
63
73
  if [ -d "$SPEC_DIR" ]; then
64
74
  SPEC_FILE=$(find "$SPEC_DIR" -name "spec-*.md" -printf "%T@ %p\n" | sort -n | tail -1 | cut -d' ' -f2-)
65
75
  if [ -z "$SPEC_FILE" ]; then
66
- # No spec files found, create first one
76
+ # No spec files found, create first one with marker for AI
67
77
  SPEC_FILE="$SPEC_DIR/spec-001.md"
68
- if [ ! -f "$TEMPLATE_FILE" ]; then
69
- error_exit "Template not found: $TEMPLATE_FILE"
70
- fi
71
- log "Creating specification from template: $SPEC_FILE"
72
- cp "$TEMPLATE_FILE" "$SPEC_FILE" || error_exit "Failed to copy specification template"
78
+ log "Creating first specification marker: $SPEC_FILE"
79
+ echo "# Specification - $FEATURE_DIR" > "$SPEC_FILE"
80
+ echo "" >> "$SPEC_FILE"
81
+ echo "<!-- AI: Please generate specification using template: $TEMPLATE_FILE -->" >> "$SPEC_FILE"
82
+ echo "<!-- FEATURE_DIR: $FEATURE_DIR -->" >> "$SPEC_FILE"
83
+ echo "<!-- FEATURE_ID: $FEATURE_ID -->" >> "$SPEC_FILE"
84
+ echo "" >> "$SPEC_FILE"
85
+ echo "## Awaiting AI Generation" >> "$SPEC_FILE"
86
+ echo "This specification needs to be generated from the template." >> "$SPEC_FILE"
73
87
  else
74
88
  log "Using latest specification: $SPEC_FILE"
75
89
  fi
76
90
  else
77
- # Create directory and first spec
91
+ # Create directory and first spec with marker for AI
78
92
  SPEC_FILE="$SPEC_DIR/spec-001.md"
79
- if [ ! -f "$TEMPLATE_FILE" ]; then
80
- error_exit "Template not found: $TEMPLATE_FILE"
81
- fi
82
- log "Creating specification from template: $SPEC_FILE"
83
- cp "$TEMPLATE_FILE" "$SPEC_FILE" || error_exit "Failed to copy specification template"
93
+ log "Creating first specification marker: $SPEC_FILE"
94
+ echo "# Specification - $FEATURE_DIR" > "$SPEC_FILE"
95
+ echo "" >> "$SPEC_FILE"
96
+ echo "<!-- AI: Please generate specification using template: $TEMPLATE_FILE -->" >> "$SPEC_FILE"
97
+ echo "<!-- FEATURE_DIR: $FEATURE_DIR -->" >> "$SPEC_FILE"
98
+ echo "<!-- FEATURE_ID: $FEATURE_ID -->" >> "$SPEC_FILE"
99
+ echo "" >> "$SPEC_FILE"
100
+ echo "## Awaiting AI Generation" >> "$SPEC_FILE"
101
+ echo "This specification needs to be generated from the template." >> "$SPEC_FILE"
84
102
  fi
85
103
  fi
86
104
 
@@ -90,18 +108,24 @@ if [ ! -f "$SPEC_FILE" ]; then
90
108
  error_exit "Specification file does not exist: $SPEC_FILE"
91
109
  fi
92
110
 
93
- # Check for required sections
94
- REQUIRED_SECTIONS=("## Specification:" "## Metadata" "## Functional Requirements" "## Acceptance Scenarios")
95
- MISSING_SECTIONS=()
111
+ # Check if file needs AI generation
112
+ if grep -q "Awaiting AI Generation" "$SPEC_FILE"; then
113
+ log "WARNING: Specification needs to be generated by AI from template"
114
+ MISSING_SECTIONS=("ALL - Awaiting AI Generation")
115
+ else
116
+ # Check for required sections only if file has been generated
117
+ REQUIRED_SECTIONS=("## Specification:" "## Metadata" "## Functional Requirements" "## Acceptance Scenarios")
118
+ MISSING_SECTIONS=()
96
119
 
97
- for section in "${REQUIRED_SECTIONS[@]}"; do
98
- if ! grep -q "$section" "$SPEC_FILE"; then
99
- MISSING_SECTIONS+=("$section")
100
- fi
101
- done
120
+ for section in "${REQUIRED_SECTIONS[@]}"; do
121
+ if ! grep -q "$section" "$SPEC_FILE"; then
122
+ MISSING_SECTIONS+=("$section")
123
+ fi
124
+ done
102
125
 
103
- if [ ${#MISSING_SECTIONS[@]} -gt 0 ]; then
104
- log "WARNING: Missing required sections: ${MISSING_SECTIONS[*]}"
126
+ if [ ${#MISSING_SECTIONS[@]} -gt 0 ]; then
127
+ log "WARNING: Missing required sections: ${MISSING_SECTIONS[*]}"
128
+ fi
105
129
  fi
106
130
 
107
131
  # Check for clarifications needed
@@ -42,8 +42,13 @@ PLAN_DIR="$PROJECT_ROOT/plans/${FEATURE_DIR}"
42
42
  SPEC_DIR="$PROJECT_ROOT/specs/${FEATURE_DIR}"
43
43
  TEMPLATE_FILE="$PROJECT_ROOT/templates/task.md"
44
44
 
45
+ # Validate template file exists before proceeding
46
+ if [ ! -f "$TEMPLATE_FILE" ]; then
47
+ error_exit "Template not found: $TEMPLATE_FILE. Please ensure templates are properly initialized."
48
+ fi
49
+
45
50
  # Ensure tasks directory exists
46
- mkdir -p "$TASK_DIR"
51
+ mkdir -p "$TASK_DIR" || error_exit "Failed to create tasks directory: $TASK_DIR"
47
52
 
48
53
  # Find latest spec file
49
54
  if [ -d "$SPEC_DIR" ]; then
@@ -67,8 +72,13 @@ fi
67
72
 
68
73
  # Find next available task number or create new one
69
74
  if [ -d "$TASK_DIR" ]; then
70
- existing_tasks=$(find "$TASK_DIR" -name "task-*.md" | wc -l)
71
- task_number=$((existing_tasks + 1))
75
+ # Get the highest task number and increment it
76
+ highest_task=$(find "$TASK_DIR" -name "task-*.md" -exec basename {} .md \; | sed 's/task-//' | sort -n | tail -1)
77
+ if [ -n "$highest_task" ]; then
78
+ task_number=$((highest_task + 1))
79
+ else
80
+ task_number=1
81
+ fi
72
82
  else
73
83
  task_number=1
74
84
  fi
@@ -79,25 +89,47 @@ if [ ! -f "$TEMPLATE_FILE" ]; then
79
89
  error_exit "Template not found: $TEMPLATE_FILE"
80
90
  fi
81
91
 
82
- # Create task file
83
- log "Creating task breakdown from template: $TASK_FILE"
84
- cp "$TEMPLATE_FILE" "$TASK_FILE" || error_exit "Failed to copy task template"
92
+ # Create task file marker for AI generation
93
+ log "Creating task breakdown marker: $TASK_FILE"
94
+ echo "# Task Breakdown - $FEATURE_DIR" > "$TASK_FILE"
95
+ echo "" >> "$TASK_FILE"
96
+ echo "<!-- AI: Please generate tasks using template: $TEMPLATE_FILE -->" >> "$TASK_FILE"
97
+ echo "<!-- SPEC_FILE: $SPEC_FILE -->" >> "$TASK_FILE"
98
+ echo "<!-- PLAN_FILE: $PLAN_FILE -->" >> "$TASK_FILE"
99
+ echo "<!-- FEATURE_DIR: $FEATURE_DIR -->" >> "$TASK_FILE"
100
+ echo "<!-- FEATURE_ID: $FEATURE_ID -->" >> "$TASK_FILE"
101
+ echo "" >> "$TASK_FILE"
102
+ echo "## Awaiting AI Generation" >> "$TASK_FILE"
103
+ echo "Tasks need to be generated from the template based on:" >> "$TASK_FILE"
104
+ echo "- Specification: $SPEC_FILE" >> "$TASK_FILE"
105
+ echo "- Plan: $PLAN_FILE" >> "$TASK_FILE"
85
106
 
86
107
  # Validate task structure
87
108
  log "Validating task breakdown..."
88
109
 
89
- # Check for required sections
90
- REQUIRED_SECTIONS=("## Task List:" "## Task Organization" "## Critical Path" "## Execution Schedule")
91
- MISSING_SECTIONS=()
92
-
93
- for section in "${REQUIRED_SECTIONS[@]}"; do
94
- if ! grep -q "$section" "$TASK_FILE"; then
95
- MISSING_SECTIONS+=("$section")
110
+ # Check if file needs AI generation
111
+ if grep -q "Awaiting AI Generation" "$TASK_FILE"; then
112
+ log "WARNING: Tasks need to be generated by AI from template"
113
+ MISSING_SECTIONS=("ALL - Awaiting AI Generation")
114
+ TOTAL_TASKS=0
115
+ COMPLETED_TASKS=0
116
+ PENDING_TASKS=0
117
+ BLOCKED_TASKS=0
118
+ PARALLEL_TASKS=0
119
+ else
120
+ # Check for required sections only if file has been generated
121
+ REQUIRED_SECTIONS=("## Task List:" "## Task Organization" "## Critical Path" "## Execution Schedule")
122
+ MISSING_SECTIONS=()
123
+
124
+ for section in "${REQUIRED_SECTIONS[@]}"; do
125
+ if ! grep -q "$section" "$TASK_FILE"; then
126
+ MISSING_SECTIONS+=("$section")
127
+ fi
128
+ done
129
+
130
+ if [ ${#MISSING_SECTIONS[@]} -gt 0 ]; then
131
+ log "WARNING: Missing required sections: ${MISSING_SECTIONS[*]}"
96
132
  fi
97
- done
98
-
99
- if [ ${#MISSING_SECTIONS[@]} -gt 0 ]; then
100
- log "WARNING: Missing required sections: ${MISSING_SECTIONS[*]}"
101
133
  fi
102
134
 
103
135
  # Count tasks and analyze structure
@@ -1,22 +1,354 @@
1
1
  openapi: 3.0.0
2
2
  info:
3
- title: {{ service_name }} API
4
- version: {{ version }}
5
- description: {{ service_description }}
6
-
3
+ title: {{service_name}} API
4
+ version: 1.0.0
5
+ description: API contract for {{service_name}} microservice
6
+ contact:
7
+ name: API Support
8
+ email: api@example.com
9
+
7
10
  servers:
8
- - url: {{ base_url }}
9
- description: {{ environment }}
11
+ - url: http://localhost:{{port}}/api/v1
12
+ description: Development server
13
+ - url: https://api.example.com/{{service_name}}/v1
14
+ description: Production server
10
15
 
11
16
  paths:
12
- {{ paths }}
17
+ /{{resource}}:
18
+ get:
19
+ summary: List all {{resource}}
20
+ operationId: list{{Resource}}
21
+ tags:
22
+ - {{Resource}}
23
+ parameters:
24
+ - in: query
25
+ name: page
26
+ schema:
27
+ type: integer
28
+ default: 1
29
+ description: Page number
30
+ - in: query
31
+ name: limit
32
+ schema:
33
+ type: integer
34
+ default: 20
35
+ maximum: 100
36
+ description: Number of items per page
37
+ - in: query
38
+ name: sort
39
+ schema:
40
+ type: string
41
+ enum: [created_at, updated_at, name]
42
+ default: created_at
43
+ description: Sort field
44
+ - in: query
45
+ name: order
46
+ schema:
47
+ type: string
48
+ enum: [asc, desc]
49
+ default: desc
50
+ description: Sort order
51
+ responses:
52
+ '200':
53
+ description: Successful response
54
+ content:
55
+ application/json:
56
+ schema:
57
+ type: object
58
+ properties:
59
+ data:
60
+ type: array
61
+ items:
62
+ $ref: '#/components/schemas/{{Resource}}'
63
+ meta:
64
+ $ref: '#/components/schemas/PaginationMeta'
65
+ '400':
66
+ $ref: '#/components/responses/BadRequest'
67
+ '401':
68
+ $ref: '#/components/responses/Unauthorized'
69
+ '500':
70
+ $ref: '#/components/responses/InternalError'
71
+
72
+ post:
73
+ summary: Create new {{resource}}
74
+ operationId: create{{Resource}}
75
+ tags:
76
+ - {{Resource}}
77
+ requestBody:
78
+ required: true
79
+ content:
80
+ application/json:
81
+ schema:
82
+ $ref: '#/components/schemas/Create{{Resource}}Request'
83
+ responses:
84
+ '201':
85
+ description: Created successfully
86
+ content:
87
+ application/json:
88
+ schema:
89
+ $ref: '#/components/schemas/{{Resource}}'
90
+ '400':
91
+ $ref: '#/components/responses/BadRequest'
92
+ '401':
93
+ $ref: '#/components/responses/Unauthorized'
94
+ '409':
95
+ $ref: '#/components/responses/Conflict'
96
+ '500':
97
+ $ref: '#/components/responses/InternalError'
98
+
99
+ /{{resource}}/{id}:
100
+ parameters:
101
+ - in: path
102
+ name: id
103
+ required: true
104
+ schema:
105
+ type: string
106
+ format: uuid
107
+ description: {{Resource}} ID
108
+
109
+ get:
110
+ summary: Get {{resource}} by ID
111
+ operationId: get{{Resource}}ById
112
+ tags:
113
+ - {{Resource}}
114
+ responses:
115
+ '200':
116
+ description: Successful response
117
+ content:
118
+ application/json:
119
+ schema:
120
+ $ref: '#/components/schemas/{{Resource}}'
121
+ '401':
122
+ $ref: '#/components/responses/Unauthorized'
123
+ '404':
124
+ $ref: '#/components/responses/NotFound'
125
+ '500':
126
+ $ref: '#/components/responses/InternalError'
127
+
128
+ put:
129
+ summary: Update {{resource}}
130
+ operationId: update{{Resource}}
131
+ tags:
132
+ - {{Resource}}
133
+ requestBody:
134
+ required: true
135
+ content:
136
+ application/json:
137
+ schema:
138
+ $ref: '#/components/schemas/Update{{Resource}}Request'
139
+ responses:
140
+ '200':
141
+ description: Updated successfully
142
+ content:
143
+ application/json:
144
+ schema:
145
+ $ref: '#/components/schemas/{{Resource}}'
146
+ '400':
147
+ $ref: '#/components/responses/BadRequest'
148
+ '401':
149
+ $ref: '#/components/responses/Unauthorized'
150
+ '404':
151
+ $ref: '#/components/responses/NotFound'
152
+ '409':
153
+ $ref: '#/components/responses/Conflict'
154
+ '500':
155
+ $ref: '#/components/responses/InternalError'
156
+
157
+ delete:
158
+ summary: Delete {{resource}}
159
+ operationId: delete{{Resource}}
160
+ tags:
161
+ - {{Resource}}
162
+ responses:
163
+ '204':
164
+ description: Deleted successfully
165
+ '401':
166
+ $ref: '#/components/responses/Unauthorized'
167
+ '404':
168
+ $ref: '#/components/responses/NotFound'
169
+ '409':
170
+ $ref: '#/components/responses/Conflict'
171
+ '500':
172
+ $ref: '#/components/responses/InternalError'
173
+
174
+ /health:
175
+ get:
176
+ summary: Health check
177
+ operationId: healthCheck
178
+ tags:
179
+ - System
180
+ responses:
181
+ '200':
182
+ description: Service is healthy
183
+ content:
184
+ application/json:
185
+ schema:
186
+ $ref: '#/components/schemas/HealthCheck'
13
187
 
14
188
  components:
15
189
  schemas:
16
- {{ schemas }}
17
-
190
+ {{Resource}}:
191
+ type: object
192
+ required:
193
+ - id
194
+ - name
195
+ - status
196
+ - created_at
197
+ - updated_at
198
+ properties:
199
+ id:
200
+ type: string
201
+ format: uuid
202
+ description: Unique identifier
203
+ name:
204
+ type: string
205
+ description: {{Resource}} name
206
+ description:
207
+ type: string
208
+ description: {{Resource}} description
209
+ status:
210
+ type: string
211
+ enum: [active, inactive, pending]
212
+ description: Current status
213
+ metadata:
214
+ type: object
215
+ additionalProperties: true
216
+ description: Additional metadata
217
+ created_at:
218
+ type: string
219
+ format: date-time
220
+ description: Creation timestamp
221
+ updated_at:
222
+ type: string
223
+ format: date-time
224
+ description: Last update timestamp
225
+
226
+ Create{{Resource}}Request:
227
+ type: object
228
+ required:
229
+ - name
230
+ properties:
231
+ name:
232
+ type: string
233
+ minLength: 1
234
+ maxLength: 255
235
+ description:
236
+ type: string
237
+ maxLength: 1000
238
+ metadata:
239
+ type: object
240
+ additionalProperties: true
241
+
242
+ Update{{Resource}}Request:
243
+ type: object
244
+ properties:
245
+ name:
246
+ type: string
247
+ minLength: 1
248
+ maxLength: 255
249
+ description:
250
+ type: string
251
+ maxLength: 1000
252
+ status:
253
+ type: string
254
+ enum: [active, inactive, pending]
255
+ metadata:
256
+ type: object
257
+ additionalProperties: true
258
+
259
+ PaginationMeta:
260
+ type: object
261
+ properties:
262
+ page:
263
+ type: integer
264
+ limit:
265
+ type: integer
266
+ total:
267
+ type: integer
268
+ total_pages:
269
+ type: integer
270
+
271
+ Error:
272
+ type: object
273
+ required:
274
+ - code
275
+ - message
276
+ properties:
277
+ code:
278
+ type: string
279
+ message:
280
+ type: string
281
+ details:
282
+ type: object
283
+ additionalProperties: true
284
+
285
+ HealthCheck:
286
+ type: object
287
+ properties:
288
+ status:
289
+ type: string
290
+ enum: [healthy, degraded, unhealthy]
291
+ version:
292
+ type: string
293
+ uptime:
294
+ type: integer
295
+ checks:
296
+ type: object
297
+ additionalProperties:
298
+ type: object
299
+ properties:
300
+ status:
301
+ type: string
302
+ message:
303
+ type: string
304
+
305
+ responses:
306
+ BadRequest:
307
+ description: Bad request
308
+ content:
309
+ application/json:
310
+ schema:
311
+ $ref: '#/components/schemas/Error'
312
+
313
+ Unauthorized:
314
+ description: Unauthorized
315
+ content:
316
+ application/json:
317
+ schema:
318
+ $ref: '#/components/schemas/Error'
319
+
320
+ NotFound:
321
+ description: Resource not found
322
+ content:
323
+ application/json:
324
+ schema:
325
+ $ref: '#/components/schemas/Error'
326
+
327
+ Conflict:
328
+ description: Conflict with current state
329
+ content:
330
+ application/json:
331
+ schema:
332
+ $ref: '#/components/schemas/Error'
333
+
334
+ InternalError:
335
+ description: Internal server error
336
+ content:
337
+ application/json:
338
+ schema:
339
+ $ref: '#/components/schemas/Error'
340
+
18
341
  securitySchemes:
19
- {{ security_schemes }}
342
+ BearerAuth:
343
+ type: http
344
+ scheme: bearer
345
+ bearerFormat: JWT
346
+
347
+ ApiKey:
348
+ type: apiKey
349
+ in: header
350
+ name: X-API-Key
20
351
 
21
- tags:
22
- {{ tags }}
352
+ security:
353
+ - BearerAuth: []
354
+ - ApiKey: []