cc-codeconductor 1.4.2 → 1.5.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.
Files changed (186) hide show
  1. package/README.md +37 -12
  2. package/dist/index.js +291 -109
  3. package/docs/generated/cli.md +8 -0
  4. package/package.json +1 -1
  5. package/presets/agy/README.md +1 -1
  6. package/presets/agy/hooks.json +1 -1
  7. package/presets/agy/scripts/invoke-hook.cjs +20 -5
  8. package/presets/agy/settings.json +1 -1
  9. package/presets/agy/skills/api-versioning/SKILL.md +394 -0
  10. package/presets/agy/skills/astro/SKILL.md +318 -0
  11. package/presets/agy/skills/auth-token-inspector/SKILL.md +30 -0
  12. package/presets/agy/skills/cc-pagespeed/SKILL.md +2 -3
  13. package/presets/agy/skills/code-review/SKILL.md +207 -0
  14. package/presets/agy/skills/django-orm/SKILL.md +460 -0
  15. package/presets/agy/skills/django-uv/SKILL.md +405 -0
  16. package/presets/agy/skills/drizzle-schema-architect/SKILL.md +50 -0
  17. package/presets/agy/skills/fastapi-pydantic-strict/SKILL.md +43 -0
  18. package/presets/agy/skills/jpa-nplusone-detector/SKILL.md +45 -0
  19. package/presets/agy/skills/jpa-postgres/SKILL.md +623 -0
  20. package/presets/agy/skills/livewire-alpine-bridge/SKILL.md +35 -0
  21. package/presets/agy/skills/nextjs-typescript/SKILL.md +390 -0
  22. package/presets/agy/skills/python/SKILL.md +611 -0
  23. package/presets/agy/skills/seo-analytics-injector/SKILL.md +43 -0
  24. package/presets/agy/skills/spring-auth-auditor/SKILL.md +29 -0
  25. package/presets/agy/skills/spring-boot-feature/SKILL.md +563 -0
  26. package/presets/agy/skills/spring-boot-testing-strategy/SKILL.md +475 -0
  27. package/presets/agy/skills/tailwind-responsive-auditor/SKILL.md +29 -0
  28. package/presets/agy/skills/tdd-mutation-tester/SKILL.md +27 -0
  29. package/presets/agy/workflows/cc-pagespeed.md +2 -3
  30. package/presets/agy/workflows/cc-review.md +31 -0
  31. package/presets/agy/workflows/cc-security.md +1 -1
  32. package/presets/claude/commands/cc/review.md +33 -0
  33. package/presets/claude/settings.json +2 -2
  34. package/presets/claude/skills/android/SKILL.md +1 -1
  35. package/presets/claude/skills/api-versioning/SKILL.md +1 -1
  36. package/presets/claude/skills/astro/SKILL.md +318 -0
  37. package/presets/claude/skills/auth-token-inspector/SKILL.md +30 -0
  38. package/presets/claude/skills/code-review/SKILL.md +207 -0
  39. package/presets/claude/skills/django-orm/SKILL.md +1 -1
  40. package/presets/claude/skills/django-testing/SKILL.md +1 -1
  41. package/presets/claude/skills/django-uv/SKILL.md +405 -0
  42. package/presets/claude/skills/drizzle-schema-architect/SKILL.md +50 -0
  43. package/presets/claude/skills/fastapi-pydantic-strict/SKILL.md +43 -0
  44. package/presets/claude/skills/jpa-nplusone-detector/SKILL.md +45 -0
  45. package/presets/claude/skills/jpa-postgres/SKILL.md +1 -1
  46. package/presets/claude/skills/livewire-alpine-bridge/SKILL.md +35 -0
  47. package/presets/claude/skills/nextjs-typescript/SKILL.md +390 -0
  48. package/presets/claude/skills/pagespeed-perf/SKILL.md +1 -1
  49. package/presets/claude/skills/python/SKILL.md +1 -1
  50. package/presets/claude/skills/python-django-stack/SKILL.md +1 -1
  51. package/presets/claude/skills/python-fastapi-stack/SKILL.md +1 -1
  52. package/presets/claude/skills/security/SKILL.md +1 -1
  53. package/presets/claude/skills/seo-analytics-injector/SKILL.md +43 -0
  54. package/presets/claude/skills/spring-auth-auditor/SKILL.md +29 -0
  55. package/presets/claude/skills/spring-boot-feature/SKILL.md +1 -1
  56. package/presets/claude/skills/spring-boot-kotlin/SKILL.md +1 -1
  57. package/presets/claude/skills/spring-boot-testing-strategy/SKILL.md +475 -0
  58. package/presets/claude/skills/sqlalchemy/SKILL.md +1 -1
  59. package/presets/claude/skills/tailwind-responsive-auditor/SKILL.md +29 -0
  60. package/presets/claude/skills/tdd-mutation-tester/SKILL.md +27 -0
  61. package/presets/claude/skills/testing-strategy/SKILL.md +1 -1
  62. package/presets/codex/skills/android/SKILL.md +1 -1
  63. package/presets/codex/skills/api-versioning/SKILL.md +1 -1
  64. package/presets/codex/skills/astro/SKILL.md +318 -0
  65. package/presets/codex/skills/auth-token-inspector/SKILL.md +30 -0
  66. package/presets/codex/skills/cc-openspec/SKILL.md +1 -1
  67. package/presets/codex/skills/cc-pagespeed/SKILL.md +2 -3
  68. package/presets/codex/skills/cc-review/SKILL.md +31 -0
  69. package/presets/codex/skills/cc-security/SKILL.md +1 -1
  70. package/presets/codex/skills/code-review/SKILL.md +207 -0
  71. package/presets/codex/skills/django-orm/SKILL.md +1 -1
  72. package/presets/codex/skills/django-testing/SKILL.md +1 -1
  73. package/presets/codex/skills/django-uv/SKILL.md +405 -0
  74. package/presets/codex/skills/drizzle-schema-architect/SKILL.md +50 -0
  75. package/presets/codex/skills/fastapi-pydantic-strict/SKILL.md +43 -0
  76. package/presets/codex/skills/jpa-nplusone-detector/SKILL.md +45 -0
  77. package/presets/codex/skills/jpa-postgres/SKILL.md +1 -1
  78. package/presets/codex/skills/livewire-alpine-bridge/SKILL.md +35 -0
  79. package/presets/codex/skills/nextjs-typescript/SKILL.md +390 -0
  80. package/presets/codex/skills/pagespeed-perf/SKILL.md +1 -1
  81. package/presets/codex/skills/python/SKILL.md +1 -1
  82. package/presets/codex/skills/python-django-stack/SKILL.md +1 -1
  83. package/presets/codex/skills/python-fastapi-stack/SKILL.md +1 -1
  84. package/presets/codex/skills/security-ai-llm/SKILL.md +43 -0
  85. package/presets/codex/skills/security-blue-team/SKILL.md +43 -0
  86. package/presets/codex/skills/security-cloud/SKILL.md +43 -0
  87. package/presets/codex/skills/security-crypto/SKILL.md +43 -0
  88. package/presets/codex/skills/security-exploit-dev/SKILL.md +45 -0
  89. package/presets/codex/skills/security-grc/SKILL.md +43 -0
  90. package/presets/codex/skills/security-incident-response/SKILL.md +45 -0
  91. package/presets/codex/skills/security-log-analysis/SKILL.md +43 -0
  92. package/presets/codex/skills/security-malware-analysis/SKILL.md +44 -0
  93. package/presets/codex/skills/security-mobile/SKILL.md +43 -0
  94. package/presets/codex/skills/security-network/SKILL.md +43 -0
  95. package/presets/codex/skills/security-ot-ics/SKILL.md +43 -0
  96. package/presets/codex/skills/security-recon/SKILL.md +45 -0
  97. package/presets/codex/skills/security-red-team/SKILL.md +44 -0
  98. package/presets/codex/skills/security-reverse-engineering/SKILL.md +44 -0
  99. package/presets/codex/skills/security-soc-automation/SKILL.md +43 -0
  100. package/presets/codex/skills/security-threat-hunting/SKILL.md +43 -0
  101. package/presets/codex/skills/security-vuln-assessment/SKILL.md +45 -0
  102. package/presets/codex/skills/security-web/SKILL.md +44 -0
  103. package/presets/codex/skills/seo-analytics-injector/SKILL.md +43 -0
  104. package/presets/codex/skills/spring-auth-auditor/SKILL.md +29 -0
  105. package/presets/codex/skills/spring-boot-feature/SKILL.md +2 -2
  106. package/presets/codex/skills/spring-boot-kotlin/SKILL.md +1 -1
  107. package/presets/codex/skills/spring-boot-testing-strategy/SKILL.md +475 -0
  108. package/presets/codex/skills/sqlalchemy/SKILL.md +1 -1
  109. package/presets/codex/skills/tailwind-responsive-auditor/SKILL.md +29 -0
  110. package/presets/codex/skills/tdd-mutation-tester/SKILL.md +27 -0
  111. package/presets/codex/skills/testing-strategy/SKILL.md +1 -1
  112. package/presets/cursor/commands/cc/openspec.md +1 -1
  113. package/presets/cursor/commands/cc/pagespeed.md +2 -3
  114. package/presets/cursor/commands/cc/review.md +31 -0
  115. package/presets/cursor/commands/cc/security.md +1 -1
  116. package/presets/cursor/skills/android/SKILL.md +1 -1
  117. package/presets/cursor/skills/api-versioning/SKILL.md +2 -1
  118. package/presets/cursor/skills/astro/SKILL.md +1 -1
  119. package/presets/cursor/skills/auth-token-inspector/SKILL.md +1 -1
  120. package/presets/cursor/skills/code-review/SKILL.md +1 -1
  121. package/presets/cursor/skills/django-orm/SKILL.md +3 -5
  122. package/presets/cursor/skills/django-testing/SKILL.md +1 -1
  123. package/presets/cursor/skills/django-uv/SKILL.md +1 -1
  124. package/presets/cursor/skills/drizzle-schema-architect/SKILL.md +1 -1
  125. package/presets/cursor/skills/fastapi-pydantic-strict/SKILL.md +1 -1
  126. package/presets/cursor/skills/jpa-nplusone-detector/SKILL.md +1 -1
  127. package/presets/cursor/skills/jpa-postgres/SKILL.md +2 -4
  128. package/presets/cursor/skills/livewire-alpine-bridge/SKILL.md +1 -1
  129. package/presets/cursor/skills/nextjs-typescript/SKILL.md +1 -1
  130. package/presets/cursor/skills/pagespeed-perf/SKILL.md +1 -1
  131. package/presets/cursor/skills/python/SKILL.md +6 -7
  132. package/presets/cursor/skills/python-django-stack/SKILL.md +1 -1
  133. package/presets/cursor/skills/python-fastapi-stack/SKILL.md +1 -1
  134. package/presets/cursor/skills/security/SKILL.md +1 -1
  135. package/presets/cursor/skills/seo-analytics-injector/SKILL.md +1 -1
  136. package/presets/cursor/skills/spring-auth-auditor/SKILL.md +1 -1
  137. package/presets/cursor/skills/spring-boot-feature/SKILL.md +2 -4
  138. package/presets/cursor/skills/spring-boot-kotlin/SKILL.md +1 -1
  139. package/presets/cursor/skills/spring-boot-testing-strategy/SKILL.md +1 -1
  140. package/presets/cursor/skills/sqlalchemy/SKILL.md +1 -1
  141. package/presets/cursor/skills/tailwind-responsive-auditor/SKILL.md +1 -1
  142. package/presets/cursor/skills/tdd-mutation-tester/SKILL.md +1 -1
  143. package/presets/gemini/commands/cc/openspec.toml +1 -1
  144. package/presets/gemini/commands/cc/pagespeed.toml +2 -3
  145. package/presets/gemini/commands/cc/review.toml +31 -0
  146. package/presets/gemini/commands/cc/security.toml +1 -1
  147. package/presets/opencode/README.md +45 -52
  148. package/presets/opencode/commands/cc-pagespeed.md +2 -3
  149. package/presets/opencode/commands/cc-review.md +31 -0
  150. package/presets/opencode/commands/cc-security.md +1 -1
  151. package/presets/opencode/opencode.jsonc +1 -1
  152. package/presets/opencode/skills/android/SKILL.md +1 -1
  153. package/presets/opencode/skills/api-versioning/SKILL.md +2 -1
  154. package/presets/opencode/skills/astro/SKILL.md +1 -1
  155. package/presets/opencode/skills/auth-token-inspector/SKILL.md +1 -1
  156. package/presets/opencode/skills/code-review/SKILL.md +1 -1
  157. package/presets/opencode/skills/django-orm/SKILL.md +3 -3
  158. package/presets/opencode/skills/django-testing/SKILL.md +1 -1
  159. package/presets/opencode/skills/django-uv/SKILL.md +1 -1
  160. package/presets/opencode/skills/drizzle-schema-architect/SKILL.md +1 -1
  161. package/presets/opencode/skills/fastapi-pydantic-strict/SKILL.md +1 -1
  162. package/presets/opencode/skills/jpa-nplusone-detector/SKILL.md +1 -1
  163. package/presets/opencode/skills/jpa-postgres/SKILL.md +2 -1
  164. package/presets/opencode/skills/livewire-alpine-bridge/SKILL.md +1 -1
  165. package/presets/opencode/skills/nextjs-typescript/SKILL.md +1 -1
  166. package/presets/opencode/skills/pagespeed-perf/SKILL.md +1 -1
  167. package/presets/opencode/skills/python/SKILL.md +6 -5
  168. package/presets/opencode/skills/python-django-stack/SKILL.md +1 -1
  169. package/presets/opencode/skills/python-fastapi-stack/SKILL.md +1 -1
  170. package/presets/opencode/skills/security/SKILL.md +1 -1
  171. package/presets/opencode/skills/seo-analytics-injector/SKILL.md +1 -1
  172. package/presets/opencode/skills/spring-auth-auditor/SKILL.md +1 -1
  173. package/presets/opencode/skills/spring-boot-feature/SKILL.md +2 -1
  174. package/presets/opencode/skills/spring-boot-kotlin/SKILL.md +1 -1
  175. package/presets/opencode/skills/spring-boot-testing-strategy/SKILL.md +1 -1
  176. package/presets/opencode/skills/sqlalchemy/SKILL.md +1 -1
  177. package/presets/opencode/skills/tailwind-responsive-auditor/SKILL.md +1 -1
  178. package/presets/opencode/skills/tdd-mutation-tester/SKILL.md +1 -1
  179. package/presets/seo-hotel/skills/astro-seo/SKILL.md +1 -1
  180. package/presets/seo-hotel/skills/geo-readiness/SKILL.md +1 -1
  181. package/presets/seo-hotel/skills/off-page/SKILL.md +1 -1
  182. package/presets/seo-hotel/skills/schema-validator/SKILL.md +1 -1
  183. package/presets/seo-hotel/skills/seo-audit/SKILL.md +1 -1
  184. package/presets/shared/invoke-hook.cjs +20 -5
  185. package/src/presets/models/roles.yml +28 -28
  186. package/src/presets/shared-skills.yml +58 -22
@@ -0,0 +1,611 @@
1
+ ---
2
+ id: python
3
+ name: python
4
+ description: >
5
+ Python development best practices: clean code, patterns,
6
+ type hints, decorators, context managers, and architecture.
7
+ Trigger: When writing Python code anywhere in the project.
8
+
9
+ user-invokable: true
10
+ license: MIT
11
+ metadata:
12
+ author: lgzarturo
13
+ category: python
14
+
15
+ compatibility:
16
+ tools: [claude, codex, gemini, agy, opencode]
17
+ stacks:
18
+ languages: [python]
19
+ frameworks: [django, fastapi, flask]
20
+
21
+ risk:
22
+ level: low
23
+ can_execute_shell: false
24
+ can_modify_files: true
25
+ requires_network: false
26
+
27
+ inputs:
28
+ - Python source files
29
+ - existing functions, classes, or modules
30
+ - business logic implementations to review or refactor
31
+
32
+ outputs:
33
+ - clean Python functions and classes with meaningful names
34
+ - type-annotated public API signatures
35
+ - custom domain exceptions
36
+ - value objects and data classes
37
+ - service and repository pattern implementations
38
+
39
+ quality:
40
+ reviewed_by: codeconductor-core
41
+ version: 0.1.0
42
+ ---
43
+
44
+ ## When to Use
45
+
46
+ - Writing any Python code in the project
47
+ - Reviewing code for quality and maintainability
48
+ - Designing new functions, classes, or modules
49
+ - Implementing business logic or utilities
50
+
51
+ ## Clean Code Principles
52
+
53
+ ### Readability > Brevity
54
+
55
+ Code is read more times than it's written. Prioritize clarity over cleverness:
56
+
57
+ ```python
58
+ # WRONG — clever but obscure
59
+ def f(x): return x if x else 0
60
+
61
+ # CORRECT — readable
62
+ def calculate_discount(price, has_discount):
63
+ if not has_discount:
64
+ return 0
65
+ return price * DISCOUNT_RATE
66
+ ```
67
+
68
+ ### Meaningful Names
69
+
70
+ | What | Convention | Example |
71
+ | --------- | ---------------------- | -------------------------------------------- |
72
+ | Variables | descriptive snake_case | `total_price`, `products_list` |
73
+ | Functions | verb snake_case | `get_active_products()`, `calculate_total()` |
74
+ | Classes | PascalCase | `OrderService`, `CartController` |
75
+ | Constants | UPPER_SNAKE_CASE | `MAX_RETRY_COUNT`, `DEFAULT_PAGE_SIZE` |
76
+ | Modules | snake_case | `order_service.py`, `cart_utils.py` |
77
+
78
+ ```python
79
+ # WRONG — cryptic names
80
+ d = 1500
81
+ p = products.filter(a=True)
82
+
83
+ # CORRECT — names that say what they are
84
+ discount_amount = 1500
85
+ active_products = Product.objects.filter(is_active=True)
86
+ ```
87
+
88
+ ### Small Functions
89
+
90
+ A function should do ONE thing. Ideally under 30 lines:
91
+
92
+ ```python
93
+ # WRONG — function does many things
94
+ def process_order(order_data):
95
+ # validates
96
+ # creates order
97
+ # creates items
98
+ # updates stock
99
+ # sends email
100
+ # updates analytics
101
+ ...
102
+
103
+ # CORRECT — small, focused functions
104
+ def process_order(order_data):
105
+ validated = validate_order_data(order_data)
106
+ order = create_order(validated)
107
+ create_order_items(order, validated["items"])
108
+ update_product_stock(validated["items"])
109
+ send_order_confirmation(order)
110
+ track_order_analytics(order)
111
+ return order
112
+ ```
113
+
114
+ ### DRY — Don't Repeat Yourself
115
+
116
+ Extract repeated code into functions or classes:
117
+
118
+ ```python
119
+ # WRONG — repeat logic
120
+ if order.status == "pending":
121
+ send_email(order.customer, "Your order is pending")
122
+ log_event("order_pending", order.id)
123
+
124
+ if order.status == "paid":
125
+ send_email(order.customer, "Your order was paid")
126
+ log_event("order_paid", order.id)
127
+
128
+ # CORRECT — extract to function
129
+ def notify_order_status(order):
130
+ status_messages = {
131
+ "pending": "Your order is pending",
132
+ "paid": "Your order was paid",
133
+ }
134
+ send_email(order.customer, status_messages[order.status])
135
+ log_event(f"order_{order.status}", order.id)
136
+ ```
137
+
138
+ ## Type Hints
139
+
140
+ ### When to Use Them
141
+
142
+ Use type hints on:
143
+
144
+ - Public function signatures (APIs, services)
145
+ - Functions with complex parameters
146
+ - Non-obvious returns
147
+
148
+ ```python
149
+ from typing import Optional, List, Dict, Any
150
+
151
+ # Public functions — use hints
152
+ def calculate_total(items: List[Dict[str, Any]], tax_rate: float) -> float:
153
+ ...
154
+
155
+ def find_product(product_id: int) -> Optional[Product]:
156
+ ...
157
+
158
+ # Private helpers — optional
159
+ def _build_cart_response(cart):
160
+ ...
161
+ ```
162
+
163
+ ### Basic Types
164
+
165
+ ```python
166
+ # Primitives
167
+ name: str = "Product"
168
+ quantity: int = 5
169
+ price: float = 1500.99
170
+ is_active: bool = True
171
+
172
+ # Collections
173
+ products: List[Product] = []
174
+ product_ids: list[int] = []
175
+ metadata: Dict[str, Any] = {}
176
+ items: tuple[str, int] = ("sku", 5)
177
+
178
+ # Optionals
179
+ user: Optional[User] = None
180
+ description: str | None = None
181
+ ```
182
+
183
+ ### Advanced Types
184
+
185
+ ```python
186
+ from typing import Union, Optional, Callable, Any
187
+ from decimal import Decimal
188
+
189
+ # Union for multiple types
190
+ def process_payment(amount: float, method: str) -> Union[dict, None]:
191
+ if method == "cash":
192
+ return {"change": amount - 1000}
193
+ return None
194
+
195
+ # Callable for functions as parameters
196
+ def execute_callback(callback: Callable[[str], None], message: str):
197
+ callback(message)
198
+
199
+ # TypeAlias for complex types
200
+ CartData = Dict[str, Dict[str, Union[int, str]]]
201
+
202
+ def process_cart(cart: CartData):
203
+ ...
204
+ ```
205
+
206
+ ## Common Patterns
207
+
208
+ ### Context Managers
209
+
210
+ For resources needing cleanup (files, connections, transactions):
211
+
212
+ ```python
213
+ # WRONG — no guaranteed cleanup
214
+ def write_report(data):
215
+ f = open("report.txt", "w")
216
+ f.write(data)
217
+ f.close() # Won't run if exception occurs
218
+
219
+ # CORRECT — context manager
220
+ def write_report(data):
221
+ with open("report.txt", "w") as f:
222
+ f.write(data)
223
+ # Automatic cleanup
224
+
225
+ # Custom context manager
226
+ class Transaction:
227
+ def __init__(self):
228
+ self.entered = False
229
+
230
+ def __enter__(self):
231
+ db.begin()
232
+ self.entered = True
233
+ return self
234
+
235
+ def __exit__(self, exc_type, exc_val, exc_tb):
236
+ if exc_type:
237
+ db.rollback()
238
+ else:
239
+ db.commit()
240
+ return False # Don't suppress exceptions
241
+ ```
242
+
243
+ ### Decorators
244
+
245
+ Functions that modify the behavior of other functions:
246
+
247
+ ```python
248
+ import functools
249
+ import time
250
+
251
+ # Basic decorator
252
+ def require_auth(view):
253
+ @functools.wraps(view)
254
+ def wrapper(request, *args, **kwargs):
255
+ if not request.user.is_authenticated:
256
+ return JsonResponse({"error": "Unauthorized"}, status=401)
257
+ return view(request, *args, **kwargs)
258
+ return wrapper
259
+
260
+ # Decorator with parameters
261
+ def require_role(role: str):
262
+ def decorator(view):
263
+ @functools.wraps(view)
264
+ def wrapper(request, *args, **kwargs):
265
+ if request.user.role != role:
266
+ return JsonResponse({"error": "Forbidden"}, status=403)
267
+ return view(request, *args, **kwargs)
268
+ return wrapper
269
+ return decorator
270
+
271
+ # Decorator with timing
272
+ def timing(view):
273
+ @functools.wraps(view)
274
+ def wrapper(*args, **kwargs):
275
+ start = time.perf_counter()
276
+ result = view(*args, **kwargs)
277
+ elapsed = time.perf_counter() - start
278
+ print(f"{view.__name__} took {elapsed:.4f}s")
279
+ return result
280
+ return wrapper
281
+ ```
282
+
283
+ ### Data Classes
284
+
285
+ For simple data structures:
286
+
287
+ ```python
288
+ from dataclasses import dataclass
289
+ from datetime import datetime
290
+ from decimal import Decimal
291
+
292
+ @dataclass
293
+ class CartItem:
294
+ product_id: int
295
+ quantity: int
296
+ price: Decimal
297
+ name: str = ""
298
+
299
+ @property
300
+ def subtotal(self) -> Decimal:
301
+ return self.price * self.quantity
302
+
303
+ # Usage
304
+ item = CartItem(product_id=1, quantity=2, price=Decimal("1500.00"))
305
+ print(item.subtotal) # 3000.00
306
+ ```
307
+
308
+ ### Enums
309
+
310
+ For limited values:
311
+
312
+ ```python
313
+ from enum import Enum
314
+
315
+ class OrderStatus(str, Enum):
316
+ PENDING = "pending"
317
+ PAID = "paid"
318
+ SHIPPED = "shipped"
319
+ CANCELLED = "cancelled"
320
+
321
+ @property
322
+ def is_final(self):
323
+ return self in (OrderStatus.SHIPPED, OrderStatus.CANCELLED)
324
+
325
+ # Usage
326
+ order.status = OrderStatus.PAID
327
+ if order.status.is_final:
328
+ ...
329
+ ```
330
+
331
+ ## Errors and Exceptions
332
+
333
+ ### Exception Handling
334
+
335
+ ```python
336
+ # WRONG — catch generic Exception
337
+ try:
338
+ product = Product.objects.get(id=product_id)
339
+ except Exception:
340
+ return JsonResponse({"error": "Not found"}, status=404)
341
+
342
+ # CORRECT — catch specific exception
343
+ try:
344
+ product = Product.objects.get(id=product_id)
345
+ except Product.DoesNotExist:
346
+ return JsonResponse({"error": "Product not found"}, status=404)
347
+
348
+ # With fallback
349
+ product = Product.objects.filter(id=product_id).first()
350
+ if not product:
351
+ return JsonResponse({"error": "Product not found"}, status=404)
352
+ ```
353
+
354
+ ### Custom Exceptions
355
+
356
+ ```python
357
+ class BusinessException(Exception):
358
+ """Exception for business logic errors."""
359
+ def __init__(self, message: str, code: str = "BUSINESS_ERROR"):
360
+ self.message = message
361
+ self.code = code
362
+ super().__init__(self.message)
363
+
364
+ class InsufficientStockException(BusinessException):
365
+ def __init__(self, product_id: int, requested: int, available: int):
366
+ super().__init__(
367
+ message=f"Insufficient stock: requested {requested}, available {available}",
368
+ code="INSUFFICIENT_STOCK",
369
+ )
370
+ self.product_id = product_id
371
+ self.requested = requested
372
+ self.available = available
373
+
374
+ # Usage
375
+ try:
376
+ if requested > available:
377
+ raise InsufficientStockException(product_id, requested, available)
378
+ except InsufficientStockException as e:
379
+ return JsonResponse({"error": e.message, "code": e.code}, status=400)
380
+ ```
381
+
382
+ ## Architecture Patterns
383
+
384
+ ### Repository Pattern
385
+
386
+ Abstract data access:
387
+
388
+ ```python
389
+ class ProductRepository:
390
+ @staticmethod
391
+ def get_active() -> QuerySet:
392
+ return Product.objects.filter(is_active=True)
393
+
394
+ @staticmethod
395
+ def get_by_category(category_id: int) -> QuerySet:
396
+ return Product.objects.filter(
397
+ category_id=category_id,
398
+ is_active=True,
399
+ ).select_related("category")
400
+
401
+ @staticmethod
402
+ def search(query: str) -> QuerySet:
403
+ return Product.objects.filter(
404
+ Q(name__icontains=query) | Q(sku__icontains=query),
405
+ is_active=True,
406
+ )
407
+ ```
408
+
409
+ ### Service Layer
410
+
411
+ Encapsulated business logic:
412
+
413
+ ```python
414
+ class ProductService:
415
+ @staticmethod
416
+ def get_products_for_pos(store: Store) -> List[Dict]:
417
+ products = ProductRepository.get_active().select_related(
418
+ "category", "tax"
419
+ )
420
+ return [
421
+ {
422
+ "id": p.id,
423
+ "name": p.name,
424
+ "price": str(p.get_display_price()),
425
+ "stock": p.stock if not p.is_service else None,
426
+ "is_service": p.is_service,
427
+ }
428
+ for p in products
429
+ ]
430
+
431
+ @staticmethod
432
+ def check_stock(product_id: int, quantity: int) -> bool:
433
+ try:
434
+ product = Product.objects.get(id=product_id)
435
+ except Product.DoesNotExist:
436
+ return False
437
+
438
+ if product.is_service:
439
+ return True
440
+ return product.stock >= quantity
441
+ ```
442
+
443
+ ### Value Objects
444
+
445
+ Immutable objects representing values:
446
+
447
+ ```python
448
+ from dataclasses import dataclass
449
+ from decimal import Decimal
450
+
451
+ @dataclass(frozen=True)
452
+ class Money:
453
+ amount: Decimal
454
+ currency: str = "ARS"
455
+
456
+ def __add__(self, other: "Money") -> "Money":
457
+ if self.currency != other.currency:
458
+ raise ValueError("Cannot add different currencies")
459
+ return Money(self.amount + other.amount, self.currency)
460
+
461
+ def __str__(self):
462
+ return f"{self.currency} {self.amount:.2f}"
463
+
464
+ # Usage
465
+ subtotal = Money(Decimal("1000.00"))
466
+ tax = Money(Decimal("210.00"))
467
+ total = subtotal + tax # Money(amount=Decimal('1210.00'), currency='ARS')
468
+ ```
469
+
470
+ ## Utility Functions
471
+
472
+ ### Common Helper Functions
473
+
474
+ ```python
475
+ import os
476
+ import json
477
+ from datetime import datetime
478
+ from decimal import Decimal
479
+ from typing import Any, Dict
480
+
481
+ def safe_int(value: Any, default: int = 0) -> int:
482
+ """Safely convert to int."""
483
+ try:
484
+ return int(value)
485
+ except (ValueError, TypeError):
486
+ return default
487
+
488
+ def safe_decimal(value: Any, default: Decimal = Decimal("0")) -> Decimal:
489
+ """Safely convert to Decimal."""
490
+ try:
491
+ return Decimal(str(value))
492
+ except (ValueError, TypeError):
493
+ return default
494
+
495
+ def format_money(amount: Decimal, currency: str = "ARS") -> str:
496
+ """Format money for display."""
497
+ return f"{currency} {amount:,.2f}".replace(",", ".")
498
+
499
+ def parse_json(body: bytes) -> Dict[str, Any]:
500
+ """Parse JSON from request body."""
501
+ try:
502
+ return json.loads(body)
503
+ except json.JSONDecodeError:
504
+ raise ValueError("Invalid JSON")
505
+
506
+ def truncate(text: str, length: int = 100, suffix: str = "...") -> str:
507
+ """Truncate text to length."""
508
+ if len(text) <= length:
509
+ return text
510
+ return text[:length - len(suffix)] + suffix
511
+ ```
512
+
513
+ ### Testing Utilities
514
+
515
+ ```python
516
+ # tests/test_utils.py
517
+ import pytest
518
+ from decimal import Decimal
519
+
520
+ class TestSafeInt:
521
+ def test_valid_int(self):
522
+ assert safe_int("42") == 42
523
+
524
+ def test_invalid_returns_default(self):
525
+ assert safe_int("not a number") == 0
526
+
527
+ def test_custom_default(self):
528
+ assert safe_int("invalid", 100) == 100
529
+
530
+ class TestMoney:
531
+ def test_add_same_currency(self):
532
+ a = Money(Decimal("100"))
533
+ b = Money(Decimal("50"))
534
+ assert a + b == Money(Decimal("150"))
535
+
536
+ def test_different_currency_raises(self):
537
+ a = Money(Decimal("100"), "ARS")
538
+ b = Money(Decimal("50"), "USD")
539
+ with pytest.raises(ValueError):
540
+ _ = a + b
541
+ ```
542
+
543
+ ## Code to Avoid
544
+
545
+ ### Mutable Default Arguments
546
+
547
+ ```python
548
+ # WRONG — mutable default
549
+ def add_items(items=[]):
550
+ items.append(1)
551
+ return items
552
+
553
+ # CORRECT
554
+ def add_items(items=None):
555
+ if items is None:
556
+ items = []
557
+ items.append(1)
558
+ return items
559
+ ```
560
+
561
+ ### Shadowing Builtins
562
+
563
+ ```python
564
+ # WRONG
565
+ list = [1, 2, 3] # shadows built-in
566
+ id = "abc" # shadows built-in
567
+
568
+ # CORRECT
569
+ items = [1, 2, 3]
570
+ product_id = "abc"
571
+ ```
572
+
573
+ ### Magic Numbers
574
+
575
+ ```python
576
+ # WRONG
577
+ if price > 1000:
578
+ discount = price * 0.1
579
+
580
+ # CORRECT
581
+ DISCOUNT_THRESHOLD = Decimal("1000")
582
+ DISCOUNT_RATE = Decimal("0.1")
583
+
584
+ if price > DISCOUNT_THRESHOLD:
585
+ discount = price * DISCOUNT_RATE
586
+ ```
587
+
588
+ ### Modifying Collections in Loop
589
+
590
+ ```python
591
+ # WRONG — modifies while iterating
592
+ for item in items:
593
+ if item.deleted:
594
+ items.remove(item)
595
+
596
+ # CORRECT
597
+ items = [item for item in items if not item.deleted]
598
+ # or
599
+ items_to_keep = []
600
+ for item in items:
601
+ if not item.deleted:
602
+ items_to_keep.append(item)
603
+ items = items_to_keep
604
+ ```
605
+
606
+ ## Resources
607
+
608
+ - **PEP 8** — Style Guide: https://peps.python.org/pep-0008/
609
+ - **PEP 484** — Type Hints: https://peps.python.org/pep-0484/
610
+ - **Real Python**: https://realpython.com/
611
+ - **Python Docs**: https://docs.python.org/3/
@@ -0,0 +1,43 @@
1
+ ---
2
+ id: seo-analytics-injector
3
+ name: seo-analytics-injector
4
+ description: >
5
+ Verifies and injects Google Tag Manager (GTM), GA4 event triggers, and optimized meta tags.
6
+ user-invokable: true
7
+ license: MIT
8
+ metadata:
9
+ author: lgzarturo
10
+ category: marketing
11
+ compatibility:
12
+ tools: [claude, codex, gemini, agy, opencode]
13
+ stacks:
14
+ languages: [typescript, javascript, html]
15
+ frameworks: [astro, nextjs]
16
+ ---
17
+ # SEO Analytics Injector
18
+
19
+ ## Core Principles
20
+
21
+ 1. **Meta tags**: Layouts must contain standard SEO meta tags (`title`, `description`, `robots`, `og:title`, `og:description`, `og:image`, `twitter:card`).
22
+ 2. **Analytics Integration**: Verify GTM container script is placed inside `<head>` (as high as possible) and the noscript iframe is placed immediately after the opening `<body>` tag.
23
+ 3. **Lighthouse Compatibility**: Ensure images have `width` and `height`, and interactive components have accessible descriptions.
24
+
25
+ ## GTM / GA4 Snippet Verification
26
+
27
+ GTM Script must match:
28
+ ```html
29
+ <!-- Google Tag Manager -->
30
+ <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
31
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
32
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
33
+ 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
34
+ })(window,document,'script','dataLayer','GTM-XXXXXX');</script>
35
+ <!-- End Google Tag Manager -->
36
+ ```
37
+ GTM Noscript must match:
38
+ ```html
39
+ <!-- Google Tag Manager (noscript) -->
40
+ <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXX"
41
+ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
42
+ <!-- End Google Tag Manager (noscript) -->
43
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ id: spring-auth-auditor
3
+ name: spring-auth-auditor
4
+ description: >
5
+ Secures Spring Security filters, JWT validations, OAuth2 setups, and CORS/CSRF headers.
6
+ user-invokable: true
7
+ license: MIT
8
+ metadata:
9
+ author: lgzarturo
10
+ category: security
11
+ compatibility:
12
+ tools: [claude, codex, gemini, agy, opencode]
13
+ stacks:
14
+ languages: [kotlin, java]
15
+ frameworks: [spring-boot, spring-security]
16
+ ---
17
+ # Spring Auth Auditor
18
+
19
+ ## Core Principles
20
+
21
+ 1. **Explicit Security Filters**: Define clear SecurityFilterChain configurations. Do not use default broad rules.
22
+ 2. **CORS & CSRF**: Always specify explicit CORS origins and keep CSRF protection enabled unless stateless API endpoints with JWT are explicitly verified.
23
+ 3. **No Mutations in Production**: Configurations must not mutate settings based on dev/prod environments dynamically in an unsafe manner.
24
+
25
+ ## Verification Checklist
26
+
27
+ - Validate JWT signature, issuer, and expiration time inside `OncePerRequestFilter`.
28
+ - Do not store JWT tokens in client-accessible localStorage. Promote Cookie-based Auth with `HttpOnly` flags.
29
+ - Ensure that endpoints matching `/api/public/**` or similar exclusions are intentionally public.