@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,491 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
AI Context Package Builder for idea2prd skills.
|
|
4
|
+
Assembles .ai-context/ directory for Vibe Coding AI agents.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import json
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from typing import List, Dict, Optional
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class BoundedContext:
|
|
17
|
+
"""Represents a bounded context."""
|
|
18
|
+
name: str
|
|
19
|
+
type: str # Core, Supporting, Generic
|
|
20
|
+
responsibility: str
|
|
21
|
+
aggregates: List[str] = field(default_factory=list)
|
|
22
|
+
events: List[str] = field(default_factory=list)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class ADRSummary:
|
|
27
|
+
"""Summary of an Architecture Decision Record."""
|
|
28
|
+
id: str
|
|
29
|
+
title: str
|
|
30
|
+
decision: str
|
|
31
|
+
rationale: str
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class FitnessRule:
|
|
36
|
+
"""A fitness rule for AI to follow."""
|
|
37
|
+
id: str
|
|
38
|
+
rule: str
|
|
39
|
+
threshold: str
|
|
40
|
+
consequence: str
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class AIContextPackage:
|
|
45
|
+
"""Complete AI context package data."""
|
|
46
|
+
product_name: str
|
|
47
|
+
description: str
|
|
48
|
+
bounded_contexts: List[BoundedContext] = field(default_factory=list)
|
|
49
|
+
adrs: List[ADRSummary] = field(default_factory=list)
|
|
50
|
+
glossary: Dict[str, str] = field(default_factory=dict)
|
|
51
|
+
coding_standards: Dict[str, str] = field(default_factory=dict)
|
|
52
|
+
fitness_rules: List[FitnessRule] = field(default_factory=list)
|
|
53
|
+
tech_stack: Dict[str, str] = field(default_factory=dict)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class AIContextBuilder:
|
|
57
|
+
"""Builds .ai-context/ package for AI agents."""
|
|
58
|
+
|
|
59
|
+
def __init__(self, package: AIContextPackage):
|
|
60
|
+
self.package = package
|
|
61
|
+
|
|
62
|
+
def build_readme(self) -> str:
|
|
63
|
+
"""Generate README.md for .ai-context/"""
|
|
64
|
+
return f"""# AI Context Package: {self.package.product_name}
|
|
65
|
+
|
|
66
|
+
This directory contains structured context for AI-assisted development (Vibe Coding).
|
|
67
|
+
|
|
68
|
+
## Contents
|
|
69
|
+
|
|
70
|
+
| File | Purpose |
|
|
71
|
+
|------|---------|
|
|
72
|
+
| `architecture-summary.md` | System overview and key components |
|
|
73
|
+
| `key-decisions.md` | Top architecture decisions (from ADRs) |
|
|
74
|
+
| `domain-glossary.md` | Ubiquitous language definitions |
|
|
75
|
+
| `bounded-contexts.md` | Context responsibilities and boundaries |
|
|
76
|
+
| `coding-standards.md` | Code style and conventions |
|
|
77
|
+
| `fitness-rules.md` | Rules AI must follow |
|
|
78
|
+
|
|
79
|
+
## Usage
|
|
80
|
+
|
|
81
|
+
When prompting AI for code generation, reference this context:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Claude Code
|
|
85
|
+
claude --context .ai-context/ "Implement [feature]"
|
|
86
|
+
|
|
87
|
+
# In conversation
|
|
88
|
+
"Using the context in .ai-context/, implement the UserAggregate"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Important Rules
|
|
92
|
+
|
|
93
|
+
1. **Follow ADRs** — All architecture decisions in `key-decisions.md` are binding
|
|
94
|
+
2. **Use Domain Language** — Terms in `domain-glossary.md` have specific meanings
|
|
95
|
+
3. **Respect Boundaries** — Don't cross bounded context boundaries directly
|
|
96
|
+
4. **Validate with Fitness** — Code must pass rules in `fitness-rules.md`
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
*Generated: {datetime.now().isoformat()}*
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
def build_architecture_summary(self) -> str:
|
|
103
|
+
"""Generate architecture-summary.md"""
|
|
104
|
+
contexts_table = "\n".join([
|
|
105
|
+
f"| {ctx.name} | {ctx.type} | {ctx.responsibility} |"
|
|
106
|
+
for ctx in self.package.bounded_contexts
|
|
107
|
+
])
|
|
108
|
+
|
|
109
|
+
tech_stack_lines = "\n".join([
|
|
110
|
+
f"- **{k}:** {v}" for k, v in self.package.tech_stack.items()
|
|
111
|
+
])
|
|
112
|
+
|
|
113
|
+
return f"""# Architecture Summary
|
|
114
|
+
|
|
115
|
+
## System Overview
|
|
116
|
+
|
|
117
|
+
**Product:** {self.package.product_name}
|
|
118
|
+
**Description:** {self.package.description}
|
|
119
|
+
|
|
120
|
+
## Technology Stack
|
|
121
|
+
|
|
122
|
+
{tech_stack_lines}
|
|
123
|
+
|
|
124
|
+
## Bounded Contexts
|
|
125
|
+
|
|
126
|
+
| Context | Type | Responsibility |
|
|
127
|
+
|---------|------|----------------|
|
|
128
|
+
{contexts_table}
|
|
129
|
+
|
|
130
|
+
## Key Integration Points
|
|
131
|
+
|
|
132
|
+
### Context Communication
|
|
133
|
+
- Contexts communicate via **Domain Events** (async)
|
|
134
|
+
- Direct API calls allowed for queries only
|
|
135
|
+
- No direct database access across contexts
|
|
136
|
+
|
|
137
|
+
### External Integrations
|
|
138
|
+
- Authentication: OAuth 2.0 / JWT
|
|
139
|
+
- Email: External service via API
|
|
140
|
+
- Storage: Cloud storage service
|
|
141
|
+
|
|
142
|
+
## Critical Constraints
|
|
143
|
+
|
|
144
|
+
1. **Single Aggregate per Transaction** — Never modify multiple aggregates in one transaction
|
|
145
|
+
2. **Event-Driven** — State changes emit domain events
|
|
146
|
+
3. **API-First** — All functionality exposed via API
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
*For detailed decisions, see `key-decisions.md`*
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
def build_key_decisions(self) -> str:
|
|
153
|
+
"""Generate key-decisions.md from ADR summaries."""
|
|
154
|
+
decisions = "\n\n".join([
|
|
155
|
+
f"""### {adr.id}: {adr.title}
|
|
156
|
+
|
|
157
|
+
**Decision:** {adr.decision}
|
|
158
|
+
|
|
159
|
+
**Rationale:** {adr.rationale}
|
|
160
|
+
"""
|
|
161
|
+
for adr in self.package.adrs
|
|
162
|
+
])
|
|
163
|
+
|
|
164
|
+
return f"""# Key Architecture Decisions
|
|
165
|
+
|
|
166
|
+
This document summarizes the most important architecture decisions.
|
|
167
|
+
For full details, see individual ADRs in `docs/adr/`.
|
|
168
|
+
|
|
169
|
+
{decisions}
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
*Total ADRs: {len(self.package.adrs)}*
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
def build_domain_glossary(self) -> str:
|
|
176
|
+
"""Generate domain-glossary.md from ubiquitous language."""
|
|
177
|
+
terms = "\n".join([
|
|
178
|
+
f"| **{term}** | {definition} |"
|
|
179
|
+
for term, definition in sorted(self.package.glossary.items())
|
|
180
|
+
])
|
|
181
|
+
|
|
182
|
+
return f"""# Domain Glossary (Ubiquitous Language)
|
|
183
|
+
|
|
184
|
+
Use these terms consistently in code, documentation, and communication.
|
|
185
|
+
|
|
186
|
+
| Term | Definition |
|
|
187
|
+
|------|------------|
|
|
188
|
+
{terms}
|
|
189
|
+
|
|
190
|
+
## Usage Guidelines
|
|
191
|
+
|
|
192
|
+
1. **In Code** — Use these exact terms for class/function/variable names
|
|
193
|
+
2. **In APIs** — Use these terms in endpoint paths and payloads
|
|
194
|
+
3. **In Documentation** — Don't use synonyms; use the defined terms
|
|
195
|
+
4. **In Communication** — Align team vocabulary with these definitions
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
*Terms: {len(self.package.glossary)}*
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
def build_bounded_contexts(self) -> str:
|
|
202
|
+
"""Generate bounded-contexts.md"""
|
|
203
|
+
contexts = []
|
|
204
|
+
|
|
205
|
+
for ctx in self.package.bounded_contexts:
|
|
206
|
+
aggregates = ", ".join(ctx.aggregates) if ctx.aggregates else "TBD"
|
|
207
|
+
events = ", ".join(ctx.events) if ctx.events else "TBD"
|
|
208
|
+
|
|
209
|
+
contexts.append(f"""### {ctx.name}
|
|
210
|
+
|
|
211
|
+
**Type:** {ctx.type}
|
|
212
|
+
**Responsibility:** {ctx.responsibility}
|
|
213
|
+
|
|
214
|
+
**Aggregates:** {aggregates}
|
|
215
|
+
**Domain Events:** {events}
|
|
216
|
+
|
|
217
|
+
**Boundaries:**
|
|
218
|
+
- Owns its own database schema
|
|
219
|
+
- Exposes API for other contexts
|
|
220
|
+
- Publishes events for state changes
|
|
221
|
+
""")
|
|
222
|
+
|
|
223
|
+
return f"""# Bounded Contexts
|
|
224
|
+
|
|
225
|
+
## Overview
|
|
226
|
+
|
|
227
|
+
This system is divided into {len(self.package.bounded_contexts)} bounded contexts.
|
|
228
|
+
|
|
229
|
+
## Context Details
|
|
230
|
+
|
|
231
|
+
{"".join(contexts)}
|
|
232
|
+
|
|
233
|
+
## Communication Rules
|
|
234
|
+
|
|
235
|
+
1. **No Direct DB Access** — Contexts don't share database tables
|
|
236
|
+
2. **API for Queries** — Use context's API to read data
|
|
237
|
+
3. **Events for Commands** — Publish events for state changes
|
|
238
|
+
4. **ACL for External** — Use Anti-Corruption Layer for external systems
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
*Contexts: {len(self.package.bounded_contexts)}*
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
def build_coding_standards(self) -> str:
|
|
245
|
+
"""Generate coding-standards.md"""
|
|
246
|
+
standards = "\n".join([
|
|
247
|
+
f"### {category}\n\n{rules}\n"
|
|
248
|
+
for category, rules in self.package.coding_standards.items()
|
|
249
|
+
])
|
|
250
|
+
|
|
251
|
+
return f"""# Coding Standards
|
|
252
|
+
|
|
253
|
+
Follow these standards when generating code.
|
|
254
|
+
|
|
255
|
+
{standards}
|
|
256
|
+
|
|
257
|
+
## File Structure
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
src/
|
|
261
|
+
├── [context]/
|
|
262
|
+
│ ├── domain/
|
|
263
|
+
│ │ ├── aggregates/
|
|
264
|
+
│ │ ├── entities/
|
|
265
|
+
│ │ ├── value-objects/
|
|
266
|
+
│ │ └── events/
|
|
267
|
+
│ ├── application/
|
|
268
|
+
│ │ ├── services/
|
|
269
|
+
│ │ └── commands/
|
|
270
|
+
│ ├── infrastructure/
|
|
271
|
+
│ │ ├── repositories/
|
|
272
|
+
│ │ └── external/
|
|
273
|
+
│ └── api/
|
|
274
|
+
│ ├── controllers/
|
|
275
|
+
│ └── dto/
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Naming Conventions
|
|
279
|
+
|
|
280
|
+
| Element | Convention | Example |
|
|
281
|
+
|---------|------------|---------|
|
|
282
|
+
| Aggregate | PascalCase | `UserAggregate` |
|
|
283
|
+
| Entity | PascalCase | `OrderItem` |
|
|
284
|
+
| Value Object | PascalCase | `EmailAddress` |
|
|
285
|
+
| Domain Event | PascalCase, past tense | `OrderPlaced` |
|
|
286
|
+
| Repository | PascalCase + Repository | `UserRepository` |
|
|
287
|
+
| Service | PascalCase + Service | `PricingService` |
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
def build_fitness_rules(self) -> str:
|
|
291
|
+
"""Generate fitness-rules.md"""
|
|
292
|
+
rules = "\n".join([
|
|
293
|
+
f"""### {rule.id}: {rule.rule}
|
|
294
|
+
|
|
295
|
+
- **Threshold:** {rule.threshold}
|
|
296
|
+
- **Consequence:** {rule.consequence}
|
|
297
|
+
"""
|
|
298
|
+
for rule in self.package.fitness_rules
|
|
299
|
+
])
|
|
300
|
+
|
|
301
|
+
return f"""# Fitness Rules
|
|
302
|
+
|
|
303
|
+
AI-generated code MUST follow these rules. Violations will be caught by automated checks.
|
|
304
|
+
|
|
305
|
+
{rules}
|
|
306
|
+
|
|
307
|
+
## Validation
|
|
308
|
+
|
|
309
|
+
All code is validated against these rules:
|
|
310
|
+
- On every commit (CI pipeline)
|
|
311
|
+
- On every PR (automated review)
|
|
312
|
+
- Before deployment (gate check)
|
|
313
|
+
|
|
314
|
+
## Consequences of Violation
|
|
315
|
+
|
|
316
|
+
| Severity | Action |
|
|
317
|
+
|----------|--------|
|
|
318
|
+
| Critical | Block merge, immediate fix required |
|
|
319
|
+
| High | Block merge, fix within 24h |
|
|
320
|
+
| Medium | Warning, fix within sprint |
|
|
321
|
+
| Low | Note for improvement |
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
*Rules: {len(self.package.fitness_rules)}*
|
|
325
|
+
"""
|
|
326
|
+
|
|
327
|
+
def build_all(self, output_dir: str = ".ai-context") -> Dict[str, str]:
|
|
328
|
+
"""Build all context files."""
|
|
329
|
+
files = {
|
|
330
|
+
"README.md": self.build_readme(),
|
|
331
|
+
"architecture-summary.md": self.build_architecture_summary(),
|
|
332
|
+
"key-decisions.md": self.build_key_decisions(),
|
|
333
|
+
"domain-glossary.md": self.build_domain_glossary(),
|
|
334
|
+
"bounded-contexts.md": self.build_bounded_contexts(),
|
|
335
|
+
"coding-standards.md": self.build_coding_standards(),
|
|
336
|
+
"fitness-rules.md": self.build_fitness_rules()
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return files
|
|
340
|
+
|
|
341
|
+
def write_to_disk(self, output_dir: str = ".ai-context"):
|
|
342
|
+
"""Write all files to disk."""
|
|
343
|
+
path = Path(output_dir)
|
|
344
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
345
|
+
|
|
346
|
+
files = self.build_all(output_dir)
|
|
347
|
+
|
|
348
|
+
for filename, content in files.items():
|
|
349
|
+
filepath = path / filename
|
|
350
|
+
filepath.write_text(content)
|
|
351
|
+
print(f"Created: {filepath}")
|
|
352
|
+
|
|
353
|
+
print(f"\n✅ AI Context Package created in {output_dir}/")
|
|
354
|
+
print(f" Files: {len(files)}")
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def create_sample_package() -> AIContextPackage:
|
|
358
|
+
"""Create a sample AI context package for demonstration."""
|
|
359
|
+
return AIContextPackage(
|
|
360
|
+
product_name="Habit Tracker",
|
|
361
|
+
description="Application for tracking daily habits with statistics and reminders",
|
|
362
|
+
bounded_contexts=[
|
|
363
|
+
BoundedContext(
|
|
364
|
+
name="Identity",
|
|
365
|
+
type="Supporting",
|
|
366
|
+
responsibility="User authentication and profile management",
|
|
367
|
+
aggregates=["User"],
|
|
368
|
+
events=["UserRegistered", "UserProfileUpdated"]
|
|
369
|
+
),
|
|
370
|
+
BoundedContext(
|
|
371
|
+
name="Habits",
|
|
372
|
+
type="Core",
|
|
373
|
+
responsibility="Habit definition and daily tracking",
|
|
374
|
+
aggregates=["Habit", "HabitLog"],
|
|
375
|
+
events=["HabitCreated", "HabitCompleted", "StreakBroken"]
|
|
376
|
+
),
|
|
377
|
+
BoundedContext(
|
|
378
|
+
name="Analytics",
|
|
379
|
+
type="Supporting",
|
|
380
|
+
responsibility="Statistics and insights generation",
|
|
381
|
+
aggregates=["UserStats"],
|
|
382
|
+
events=["StatsUpdated", "InsightGenerated"]
|
|
383
|
+
)
|
|
384
|
+
],
|
|
385
|
+
adrs=[
|
|
386
|
+
ADRSummary(
|
|
387
|
+
id="ADR-001",
|
|
388
|
+
title="Modular Monolith Architecture",
|
|
389
|
+
decision="Use modular monolith with clear bounded context boundaries",
|
|
390
|
+
rationale="Simpler deployment for MVP while maintaining clean architecture"
|
|
391
|
+
),
|
|
392
|
+
ADRSummary(
|
|
393
|
+
id="ADR-002",
|
|
394
|
+
title="PostgreSQL Database",
|
|
395
|
+
decision="Use PostgreSQL as primary database",
|
|
396
|
+
rationale="ACID compliance, JSON support, and team expertise"
|
|
397
|
+
),
|
|
398
|
+
ADRSummary(
|
|
399
|
+
id="ADR-003",
|
|
400
|
+
title="REST API",
|
|
401
|
+
decision="Use REST with JSON for API design",
|
|
402
|
+
rationale="Simple, widely supported, good tooling"
|
|
403
|
+
),
|
|
404
|
+
ADRSummary(
|
|
405
|
+
id="ADR-004",
|
|
406
|
+
title="JWT Authentication",
|
|
407
|
+
decision="Use JWT tokens with OAuth 2.0 for authentication",
|
|
408
|
+
rationale="Stateless, mobile-friendly, standard approach"
|
|
409
|
+
)
|
|
410
|
+
],
|
|
411
|
+
glossary={
|
|
412
|
+
"Habit": "A recurring activity that user wants to track",
|
|
413
|
+
"Streak": "Consecutive days of completing a habit",
|
|
414
|
+
"Check-in": "Recording completion of a habit for a specific day",
|
|
415
|
+
"Reminder": "Notification to prompt user to complete a habit",
|
|
416
|
+
"Insight": "AI-generated observation about user's habit patterns"
|
|
417
|
+
},
|
|
418
|
+
coding_standards={
|
|
419
|
+
"TypeScript": """- Use strict mode
|
|
420
|
+
- Prefer `interface` over `type` for object shapes
|
|
421
|
+
- Use `readonly` for immutable properties
|
|
422
|
+
- Explicit return types for public functions""",
|
|
423
|
+
"Testing": """- Unit tests for domain logic (Jest)
|
|
424
|
+
- Integration tests for repositories
|
|
425
|
+
- E2E tests for critical user journeys
|
|
426
|
+
- Minimum 80% coverage""",
|
|
427
|
+
"Error Handling": """- Use custom error classes per bounded context
|
|
428
|
+
- Return RFC 7807 Problem Details from API
|
|
429
|
+
- Log errors with correlation ID"""
|
|
430
|
+
},
|
|
431
|
+
fitness_rules=[
|
|
432
|
+
FitnessRule(
|
|
433
|
+
id="FF-001",
|
|
434
|
+
rule="No cross-context database access",
|
|
435
|
+
threshold="0 violations",
|
|
436
|
+
consequence="Block merge"
|
|
437
|
+
),
|
|
438
|
+
FitnessRule(
|
|
439
|
+
id="FF-002",
|
|
440
|
+
rule="Aggregates must have ≤7 entities",
|
|
441
|
+
threshold="7 entities max",
|
|
442
|
+
consequence="Code review required"
|
|
443
|
+
),
|
|
444
|
+
FitnessRule(
|
|
445
|
+
id="FF-003",
|
|
446
|
+
rule="All private endpoints require authentication",
|
|
447
|
+
threshold="100% coverage",
|
|
448
|
+
consequence="Block merge"
|
|
449
|
+
),
|
|
450
|
+
FitnessRule(
|
|
451
|
+
id="FF-004",
|
|
452
|
+
rule="Test coverage minimum",
|
|
453
|
+
threshold="≥80%",
|
|
454
|
+
consequence="Block merge"
|
|
455
|
+
)
|
|
456
|
+
],
|
|
457
|
+
tech_stack={
|
|
458
|
+
"Backend": "Node.js + Express + TypeScript",
|
|
459
|
+
"Database": "PostgreSQL",
|
|
460
|
+
"Cache": "Redis",
|
|
461
|
+
"Frontend": "React + TypeScript",
|
|
462
|
+
"API": "REST + JSON",
|
|
463
|
+
"Auth": "JWT + OAuth 2.0",
|
|
464
|
+
"Testing": "Jest + Playwright"
|
|
465
|
+
}
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
# =============================================================================
|
|
470
|
+
# Main / Example Usage
|
|
471
|
+
# =============================================================================
|
|
472
|
+
|
|
473
|
+
if __name__ == "__main__":
|
|
474
|
+
# Create sample package
|
|
475
|
+
package = create_sample_package()
|
|
476
|
+
|
|
477
|
+
# Build context
|
|
478
|
+
builder = AIContextBuilder(package)
|
|
479
|
+
|
|
480
|
+
# Print all files
|
|
481
|
+
files = builder.build_all()
|
|
482
|
+
|
|
483
|
+
for filename, content in files.items():
|
|
484
|
+
print("=" * 60)
|
|
485
|
+
print(f"FILE: {filename}")
|
|
486
|
+
print("=" * 60)
|
|
487
|
+
print(content)
|
|
488
|
+
print()
|
|
489
|
+
|
|
490
|
+
# Optionally write to disk
|
|
491
|
+
# builder.write_to_disk(".ai-context")
|