@dzhechkov/skills-idea2prd 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +71 -0
- package/bin/cli.js +5 -0
- package/package.json +49 -0
- package/sources.json +25 -0
- package/src/cli.js +108 -0
- package/src/commands/doctor.js +340 -0
- package/src/commands/init.js +168 -0
- package/src/commands/list.js +146 -0
- package/src/commands/remove.js +182 -0
- package/src/commands/update.js +170 -0
- package/src/utils.js +154 -0
- package/templates/.claude/commands/idea2prd-manual.md +35 -0
- package/templates/.claude/skills/explore/SKILL.md +218 -0
- package/templates/.claude/skills/explore/references/questioning-techniques.md +151 -0
- package/templates/.claude/skills/explore/references/task-brief-templates.md +355 -0
- package/templates/.claude/skills/goap-research-ed25519/SKILL.md +418 -0
- package/templates/.claude/skills/goap-research-ed25519/references/ed25519-verification.md +658 -0
- package/templates/.claude/skills/goap-research-ed25519/references/research-actions.md +544 -0
- package/templates/.claude/skills/goap-research-ed25519/references/source-evaluation.md +560 -0
- package/templates/.claude/skills/goap-research-ed25519/scripts/ed25519_verifier.py +662 -0
- package/templates/.claude/skills/goap-research-ed25519/scripts/goap_planner.py +720 -0
- package/templates/.claude/skills/idea2prd-manual/SKILL.md +695 -0
- package/templates/.claude/skills/idea2prd-manual/references/adr-catalog.md +288 -0
- package/templates/.claude/skills/idea2prd-manual/references/c4-model.md +277 -0
- package/templates/.claude/skills/idea2prd-manual/references/completion-checklist-template.md +446 -0
- package/templates/.claude/skills/idea2prd-manual/references/ddd-patterns.md +261 -0
- package/templates/.claude/skills/idea2prd-manual/references/fitness-functions-catalog.md +414 -0
- package/templates/.claude/skills/idea2prd-manual/references/pseudocode-style.md +404 -0
- package/templates/.claude/skills/idea2prd-manual/scripts/ai_context_builder.py +491 -0
- package/templates/.claude/skills/idea2prd-manual/scripts/c4_generator.py +311 -0
- package/templates/.claude/skills/idea2prd-manual/scripts/fitness_validator.py +451 -0
- package/templates/.claude/skills/idea2prd-manual/scripts/pseudocode_generator.py +430 -0
- package/templates/.claude/skills/problem-solver-enhanced/SKILL.md +565 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
# Pseudocode Style Guide
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Pseudocode в idea2prd используется для:
|
|
6
|
+
1. Точного описания алгоритмов до написания кода
|
|
7
|
+
2. Улучшения качества генерации кода в Claude Code (+99% по исследованиям)
|
|
8
|
+
3. Документирования business logic
|
|
9
|
+
|
|
10
|
+
## Syntax Conventions
|
|
11
|
+
|
|
12
|
+
### Function Definition
|
|
13
|
+
|
|
14
|
+
```pseudocode
|
|
15
|
+
FUNCTION functionName(param1: Type, param2: Type) -> ReturnType:
|
|
16
|
+
// Function body
|
|
17
|
+
END FUNCTION
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Aggregate Definition
|
|
21
|
+
|
|
22
|
+
```pseudocode
|
|
23
|
+
AGGREGATE AggregateName
|
|
24
|
+
|
|
25
|
+
// State
|
|
26
|
+
STATE:
|
|
27
|
+
id: AggregateId
|
|
28
|
+
status: Status
|
|
29
|
+
items: List<Item>
|
|
30
|
+
END STATE
|
|
31
|
+
|
|
32
|
+
// Constructor
|
|
33
|
+
FUNCTION create(...) -> AggregateName:
|
|
34
|
+
...
|
|
35
|
+
END FUNCTION
|
|
36
|
+
|
|
37
|
+
// Commands
|
|
38
|
+
FUNCTION commandMethod(...) -> void:
|
|
39
|
+
...
|
|
40
|
+
END FUNCTION
|
|
41
|
+
|
|
42
|
+
// Queries
|
|
43
|
+
FUNCTION queryMethod(...) -> ReturnType:
|
|
44
|
+
...
|
|
45
|
+
END FUNCTION
|
|
46
|
+
|
|
47
|
+
END AGGREGATE
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Control Structures
|
|
51
|
+
|
|
52
|
+
```pseudocode
|
|
53
|
+
// Conditionals
|
|
54
|
+
IF condition THEN
|
|
55
|
+
action
|
|
56
|
+
ELSE IF other_condition THEN
|
|
57
|
+
other_action
|
|
58
|
+
ELSE
|
|
59
|
+
default_action
|
|
60
|
+
END IF
|
|
61
|
+
|
|
62
|
+
// Loops
|
|
63
|
+
FOR each item IN collection:
|
|
64
|
+
process(item)
|
|
65
|
+
END FOR
|
|
66
|
+
|
|
67
|
+
FOR i FROM 1 TO n:
|
|
68
|
+
process(i)
|
|
69
|
+
END FOR
|
|
70
|
+
|
|
71
|
+
WHILE condition:
|
|
72
|
+
action
|
|
73
|
+
END WHILE
|
|
74
|
+
|
|
75
|
+
// Early returns
|
|
76
|
+
IF invalid THEN
|
|
77
|
+
RETURN error
|
|
78
|
+
END IF
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Validation
|
|
82
|
+
|
|
83
|
+
```pseudocode
|
|
84
|
+
// Pre-conditions at start of function
|
|
85
|
+
VALIDATE param IS NOT empty ELSE throw ValidationError("param required")
|
|
86
|
+
VALIDATE param.value > 0 ELSE throw ValidationError("must be positive")
|
|
87
|
+
VALIDATE user.hasPermission(action) ELSE throw UnauthorizedError
|
|
88
|
+
|
|
89
|
+
// Post-conditions before return
|
|
90
|
+
ENSURE result IS valid
|
|
91
|
+
ENSURE result.count > 0
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Domain Events
|
|
95
|
+
|
|
96
|
+
```pseudocode
|
|
97
|
+
// Emit domain event
|
|
98
|
+
EMIT EventName(
|
|
99
|
+
aggregateId: this.id,
|
|
100
|
+
timestamp: NOW(),
|
|
101
|
+
data: relevant_data
|
|
102
|
+
)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### External Calls
|
|
106
|
+
|
|
107
|
+
```pseudocode
|
|
108
|
+
// Repository calls
|
|
109
|
+
entity = repository.findById(id)
|
|
110
|
+
repository.save(entity)
|
|
111
|
+
|
|
112
|
+
// Service calls
|
|
113
|
+
result = externalService.call(params)
|
|
114
|
+
|
|
115
|
+
// Async operations
|
|
116
|
+
ASYNC:
|
|
117
|
+
result = await longRunningOperation()
|
|
118
|
+
END ASYNC
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Error Handling
|
|
122
|
+
|
|
123
|
+
```pseudocode
|
|
124
|
+
TRY:
|
|
125
|
+
riskyOperation()
|
|
126
|
+
CATCH SpecificError AS e:
|
|
127
|
+
handleSpecificError(e)
|
|
128
|
+
CATCH:
|
|
129
|
+
handleGenericError()
|
|
130
|
+
FINALLY:
|
|
131
|
+
cleanup()
|
|
132
|
+
END TRY
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Required Sections
|
|
136
|
+
|
|
137
|
+
Each pseudocode file MUST include:
|
|
138
|
+
|
|
139
|
+
1. **Pre-conditions** - What must be true before execution
|
|
140
|
+
2. **Main logic** - The algorithm steps
|
|
141
|
+
3. **Post-conditions** - What must be true after execution
|
|
142
|
+
4. **Events** - Domain events emitted
|
|
143
|
+
|
|
144
|
+
## Example: Complete Aggregate
|
|
145
|
+
|
|
146
|
+
```pseudocode
|
|
147
|
+
// File: OrderAggregate.pseudo
|
|
148
|
+
|
|
149
|
+
AGGREGATE Order
|
|
150
|
+
|
|
151
|
+
STATE:
|
|
152
|
+
id: OrderId
|
|
153
|
+
customerId: CustomerId
|
|
154
|
+
items: List<OrderItem>
|
|
155
|
+
status: OrderStatus // DRAFT, PLACED, CONFIRMED, SHIPPED, DELIVERED, CANCELLED
|
|
156
|
+
subtotal: Money
|
|
157
|
+
tax: Money
|
|
158
|
+
total: Money
|
|
159
|
+
createdAt: DateTime
|
|
160
|
+
updatedAt: DateTime
|
|
161
|
+
END STATE
|
|
162
|
+
|
|
163
|
+
//========================================
|
|
164
|
+
// COMMAND: Place Order
|
|
165
|
+
//========================================
|
|
166
|
+
FUNCTION placeOrder(items: List<OrderItem>, customer: Customer) -> OrderId:
|
|
167
|
+
|
|
168
|
+
// Pre-conditions
|
|
169
|
+
VALIDATE items IS NOT empty
|
|
170
|
+
ELSE throw EmptyOrderError("Order must have at least one item")
|
|
171
|
+
|
|
172
|
+
VALIDATE customer.isVerified
|
|
173
|
+
ELSE throw UnverifiedCustomerError("Customer must be verified to place orders")
|
|
174
|
+
|
|
175
|
+
VALIDATE customer.hasValidPaymentMethod
|
|
176
|
+
ELSE throw NoPaymentMethodError("Customer must have valid payment method")
|
|
177
|
+
|
|
178
|
+
// Check inventory for all items
|
|
179
|
+
FOR each item IN items:
|
|
180
|
+
available = inventoryService.checkStock(item.productId, item.quantity)
|
|
181
|
+
IF NOT available THEN
|
|
182
|
+
throw OutOfStockError(item.productId, item.quantity)
|
|
183
|
+
END IF
|
|
184
|
+
END FOR
|
|
185
|
+
|
|
186
|
+
// Calculate totals
|
|
187
|
+
subtotal = 0
|
|
188
|
+
FOR each item IN items:
|
|
189
|
+
subtotal = subtotal + (item.unitPrice * item.quantity)
|
|
190
|
+
END FOR
|
|
191
|
+
|
|
192
|
+
tax = taxService.calculate(subtotal, customer.shippingAddress.region)
|
|
193
|
+
total = subtotal + tax
|
|
194
|
+
|
|
195
|
+
// Validate order limits
|
|
196
|
+
VALIDATE total >= MINIMUM_ORDER_AMOUNT
|
|
197
|
+
ELSE throw MinimumOrderError(MINIMUM_ORDER_AMOUNT)
|
|
198
|
+
|
|
199
|
+
VALIDATE total <= customer.creditLimit
|
|
200
|
+
ELSE throw CreditLimitExceededError(customer.creditLimit)
|
|
201
|
+
|
|
202
|
+
// Create order
|
|
203
|
+
this.id = generateOrderId()
|
|
204
|
+
this.customerId = customer.id
|
|
205
|
+
this.items = items
|
|
206
|
+
this.status = PLACED
|
|
207
|
+
this.subtotal = subtotal
|
|
208
|
+
this.tax = tax
|
|
209
|
+
this.total = total
|
|
210
|
+
this.createdAt = NOW()
|
|
211
|
+
this.updatedAt = NOW()
|
|
212
|
+
|
|
213
|
+
// Reserve inventory
|
|
214
|
+
FOR each item IN items:
|
|
215
|
+
inventoryService.reserve(item.productId, item.quantity, this.id)
|
|
216
|
+
END FOR
|
|
217
|
+
|
|
218
|
+
// Post-conditions
|
|
219
|
+
ENSURE this.status == PLACED
|
|
220
|
+
ENSURE this.total == subtotal + tax
|
|
221
|
+
|
|
222
|
+
// Emit event
|
|
223
|
+
EMIT OrderPlacedEvent(
|
|
224
|
+
orderId: this.id,
|
|
225
|
+
customerId: customer.id,
|
|
226
|
+
items: items.map(i => {productId: i.productId, quantity: i.quantity}),
|
|
227
|
+
total: this.total,
|
|
228
|
+
timestamp: NOW()
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
RETURN this.id
|
|
232
|
+
END FUNCTION
|
|
233
|
+
|
|
234
|
+
//========================================
|
|
235
|
+
// COMMAND: Confirm Order
|
|
236
|
+
//========================================
|
|
237
|
+
FUNCTION confirm(paymentId: PaymentId) -> void:
|
|
238
|
+
|
|
239
|
+
// Pre-conditions
|
|
240
|
+
VALIDATE this.status == PLACED
|
|
241
|
+
ELSE throw InvalidStateError("Can only confirm PLACED orders")
|
|
242
|
+
|
|
243
|
+
VALIDATE paymentId IS NOT null
|
|
244
|
+
ELSE throw ValidationError("Payment ID required")
|
|
245
|
+
|
|
246
|
+
// Verify payment
|
|
247
|
+
payment = paymentService.getPayment(paymentId)
|
|
248
|
+
VALIDATE payment.status == SUCCESSFUL
|
|
249
|
+
ELSE throw PaymentFailedError(paymentId)
|
|
250
|
+
|
|
251
|
+
VALIDATE payment.amount == this.total
|
|
252
|
+
ELSE throw PaymentAmountMismatchError(payment.amount, this.total)
|
|
253
|
+
|
|
254
|
+
// Update state
|
|
255
|
+
this.status = CONFIRMED
|
|
256
|
+
this.paymentId = paymentId
|
|
257
|
+
this.updatedAt = NOW()
|
|
258
|
+
|
|
259
|
+
// Post-conditions
|
|
260
|
+
ENSURE this.status == CONFIRMED
|
|
261
|
+
|
|
262
|
+
// Emit event
|
|
263
|
+
EMIT OrderConfirmedEvent(
|
|
264
|
+
orderId: this.id,
|
|
265
|
+
paymentId: paymentId,
|
|
266
|
+
timestamp: NOW()
|
|
267
|
+
)
|
|
268
|
+
END FUNCTION
|
|
269
|
+
|
|
270
|
+
//========================================
|
|
271
|
+
// COMMAND: Cancel Order
|
|
272
|
+
//========================================
|
|
273
|
+
FUNCTION cancel(reason: CancellationReason) -> void:
|
|
274
|
+
|
|
275
|
+
// Pre-conditions
|
|
276
|
+
VALIDATE this.status IN [PLACED, CONFIRMED]
|
|
277
|
+
ELSE throw InvalidStateError("Cannot cancel order in status: " + this.status)
|
|
278
|
+
|
|
279
|
+
VALIDATE reason IS NOT null
|
|
280
|
+
ELSE throw ValidationError("Cancellation reason required")
|
|
281
|
+
|
|
282
|
+
// Release inventory reservations
|
|
283
|
+
FOR each item IN this.items:
|
|
284
|
+
inventoryService.release(item.productId, item.quantity, this.id)
|
|
285
|
+
END FOR
|
|
286
|
+
|
|
287
|
+
// Process refund if payment was made
|
|
288
|
+
IF this.status == CONFIRMED AND this.paymentId IS NOT null THEN
|
|
289
|
+
refundId = paymentService.refund(this.paymentId, this.total)
|
|
290
|
+
END IF
|
|
291
|
+
|
|
292
|
+
// Update state
|
|
293
|
+
previousStatus = this.status
|
|
294
|
+
this.status = CANCELLED
|
|
295
|
+
this.cancellationReason = reason
|
|
296
|
+
this.cancelledAt = NOW()
|
|
297
|
+
this.updatedAt = NOW()
|
|
298
|
+
|
|
299
|
+
// Post-conditions
|
|
300
|
+
ENSURE this.status == CANCELLED
|
|
301
|
+
|
|
302
|
+
// Emit event
|
|
303
|
+
EMIT OrderCancelledEvent(
|
|
304
|
+
orderId: this.id,
|
|
305
|
+
previousStatus: previousStatus,
|
|
306
|
+
reason: reason,
|
|
307
|
+
refundId: refundId, // may be null
|
|
308
|
+
timestamp: NOW()
|
|
309
|
+
)
|
|
310
|
+
END FUNCTION
|
|
311
|
+
|
|
312
|
+
//========================================
|
|
313
|
+
// QUERY: Calculate Estimated Delivery
|
|
314
|
+
//========================================
|
|
315
|
+
FUNCTION getEstimatedDelivery() -> DateRange:
|
|
316
|
+
|
|
317
|
+
// Pre-conditions
|
|
318
|
+
VALIDATE this.status IN [CONFIRMED, SHIPPED]
|
|
319
|
+
ELSE throw InvalidStateError("No delivery estimate for status: " + this.status)
|
|
320
|
+
|
|
321
|
+
// Get shipping method
|
|
322
|
+
shippingMethod = this.shippingMethod OR DEFAULT_SHIPPING
|
|
323
|
+
|
|
324
|
+
// Calculate based on items and destination
|
|
325
|
+
maxLeadTime = 0
|
|
326
|
+
FOR each item IN this.items:
|
|
327
|
+
product = productService.getProduct(item.productId)
|
|
328
|
+
IF product.leadTimeDays > maxLeadTime THEN
|
|
329
|
+
maxLeadTime = product.leadTimeDays
|
|
330
|
+
END IF
|
|
331
|
+
END FOR
|
|
332
|
+
|
|
333
|
+
transitTime = shippingService.getTransitTime(
|
|
334
|
+
shippingMethod,
|
|
335
|
+
this.shippingAddress
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
earliestDate = NOW() + maxLeadTime + transitTime.min
|
|
339
|
+
latestDate = NOW() + maxLeadTime + transitTime.max
|
|
340
|
+
|
|
341
|
+
RETURN DateRange(earliestDate, latestDate)
|
|
342
|
+
END FUNCTION
|
|
343
|
+
|
|
344
|
+
END AGGREGATE
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Coverage Requirements
|
|
348
|
+
|
|
349
|
+
| Element | Pseudocode Required |
|
|
350
|
+
|---------|---------------------|
|
|
351
|
+
| Aggregate command methods | ✅ Always |
|
|
352
|
+
| Aggregate factory methods | ✅ Always |
|
|
353
|
+
| Domain Service public methods | ✅ Always |
|
|
354
|
+
| Complex query methods | ✅ If business logic |
|
|
355
|
+
| Simple getters | ❌ Not needed |
|
|
356
|
+
| Infrastructure code | ❌ Not needed |
|
|
357
|
+
|
|
358
|
+
## Integration with Claude Code
|
|
359
|
+
|
|
360
|
+
When implementing from pseudocode:
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
# Reference pseudocode directly
|
|
364
|
+
claude "Implement OrderAggregate.placeOrder() in TypeScript following @docs/pseudocode/OrderAggregate.pseudo"
|
|
365
|
+
|
|
366
|
+
# Generate with specific framework
|
|
367
|
+
claude "Convert @docs/pseudocode/OrderAggregate.pseudo to NestJS with TypeORM"
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Anti-Patterns to Avoid
|
|
371
|
+
|
|
372
|
+
❌ **Too vague:**
|
|
373
|
+
```pseudocode
|
|
374
|
+
FUNCTION placeOrder():
|
|
375
|
+
do stuff
|
|
376
|
+
return order
|
|
377
|
+
END FUNCTION
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
❌ **Implementation details:**
|
|
381
|
+
```pseudocode
|
|
382
|
+
FUNCTION placeOrder():
|
|
383
|
+
const order = new Order() // Don't use language syntax
|
|
384
|
+
order.id = uuid.v4() // Don't specify libraries
|
|
385
|
+
END FUNCTION
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
✅ **Just right:**
|
|
389
|
+
```pseudocode
|
|
390
|
+
FUNCTION placeOrder(items, customer) -> OrderId:
|
|
391
|
+
VALIDATE items not empty
|
|
392
|
+
VALIDATE customer.isVerified
|
|
393
|
+
|
|
394
|
+
FOR each item IN items:
|
|
395
|
+
CHECK inventory.hasStock(item)
|
|
396
|
+
END FOR
|
|
397
|
+
|
|
398
|
+
total = CALCULATE subtotal + tax
|
|
399
|
+
order = CREATE Order(customer, items, total)
|
|
400
|
+
|
|
401
|
+
EMIT OrderPlacedEvent(order.id, total)
|
|
402
|
+
RETURN order.id
|
|
403
|
+
END FUNCTION
|
|
404
|
+
```
|