claude-autopm 1.18.0 → 1.20.1

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 (108) hide show
  1. package/README.md +159 -0
  2. package/autopm/.claude/agents/README.md +1 -1
  3. package/autopm/.claude/agents/core/mcp-manager.md +1 -1
  4. package/autopm/.claude/agents/decision-matrices/python-backend-selection.md +25 -25
  5. package/autopm/.claude/agents/decision-matrices/ui-framework-selection.md +43 -43
  6. package/autopm/.claude/agents/devops/github-operations-specialist.md +1 -1
  7. package/autopm/.claude/agents/frameworks/README.md +5 -5
  8. package/autopm/.claude/agents/frameworks/e2e-test-engineer.md +1 -1
  9. package/autopm/.claude/agents/frameworks/nats-messaging-expert.md +1 -1
  10. package/autopm/.claude/agents/frameworks/react-frontend-engineer.md +1 -1
  11. package/autopm/.claude/agents/frameworks/react-ui-expert.md +3 -3
  12. package/autopm/.claude/agents/frameworks/tailwindcss-expert.md +3 -3
  13. package/autopm/.claude/agents/frameworks/ux-design-expert.md +3 -3
  14. package/autopm/.claude/commands/infrastructure/traefik-setup.md +1 -1
  15. package/autopm/.claude/commands/playwright/test-scaffold.md +1 -1
  16. package/autopm/.claude/commands/pm/context.md +11 -0
  17. package/autopm/.claude/commands/pm/epic-decompose.md +25 -2
  18. package/autopm/.claude/commands/pm/epic-oneshot.md +13 -0
  19. package/autopm/.claude/commands/pm/epic-start.md +19 -0
  20. package/autopm/.claude/commands/pm/epic-sync-modular.md +10 -10
  21. package/autopm/.claude/commands/pm/epic-sync.md +14 -14
  22. package/autopm/.claude/commands/pm/issue-start.md +50 -5
  23. package/autopm/.claude/commands/pm/issue-sync.md +15 -15
  24. package/autopm/.claude/commands/pm/what-next.md +11 -0
  25. package/autopm/.claude/commands/ui/bootstrap-scaffold.md +6 -5
  26. package/autopm/.claude/commands/ui/tailwind-system.md +1 -1
  27. package/autopm/.claude/examples/mcp/playwright-mcp.md +2 -2
  28. package/autopm/.claude/examples/mcp-servers.example.json +2 -2
  29. package/autopm/.claude/hooks/docker-first-enforcement.sh +1 -1
  30. package/autopm/.claude/mcp/MCP-REGISTRY.md +1 -1
  31. package/autopm/.claude/mcp/playwright-mcp.md +2 -2
  32. package/autopm/.claude/rules/agent-coordination.md +26 -24
  33. package/autopm/.claude/rules/docker-first-development.md +1 -1
  34. package/autopm/.claude/rules/infrastructure-pipeline.md +1 -1
  35. package/autopm/.claude/rules/ui-development-standards.md +1 -1
  36. package/autopm/.claude/rules/visual-testing.md +3 -3
  37. package/autopm/.claude/scripts/azure/active-work.js +2 -2
  38. package/autopm/.claude/scripts/azure/blocked.js +13 -13
  39. package/autopm/.claude/scripts/azure/daily.js +1 -1
  40. package/autopm/.claude/scripts/azure/dashboard.js +1 -1
  41. package/autopm/.claude/scripts/azure/feature-list.js +2 -2
  42. package/autopm/.claude/scripts/azure/feature-status.js +1 -1
  43. package/autopm/.claude/scripts/azure/next-task.js +1 -1
  44. package/autopm/.claude/scripts/azure/search.js +1 -1
  45. package/autopm/.claude/scripts/azure/setup.js +15 -15
  46. package/autopm/.claude/scripts/azure/sprint-report.js +2 -2
  47. package/autopm/.claude/scripts/azure/sync.js +1 -1
  48. package/autopm/.claude/scripts/azure/us-list.js +1 -1
  49. package/autopm/.claude/scripts/azure/us-status.js +1 -1
  50. package/autopm/.claude/scripts/azure/validate.js +13 -13
  51. package/autopm/.claude/scripts/lib/frontmatter-utils.sh +42 -7
  52. package/autopm/.claude/scripts/lib/logging-utils.sh +20 -16
  53. package/autopm/.claude/scripts/lib/validation-utils.sh +1 -1
  54. package/autopm/.claude/scripts/pm/context.js +338 -0
  55. package/autopm/.claude/scripts/pm/issue-sync/format-comment.sh +3 -3
  56. package/autopm/.claude/scripts/pm/lib/README.md +85 -0
  57. package/autopm/.claude/scripts/pm/lib/logger.js +78 -0
  58. package/autopm/.claude/scripts/pm/next.js +25 -1
  59. package/autopm/.claude/scripts/pm/what-next.js +660 -0
  60. package/autopm/.claude/teams.json +3 -5
  61. package/autopm/.claude/templates/claude-templates/addons/devops-agents.md +2 -2
  62. package/autopm/.claude/templates/claude-templates/addons/docker-agents.md +4 -4
  63. package/autopm/.claude/templates/claude-templates/addons/minimal-agents.md +1 -1
  64. package/autopm/.claude/templates/issue-decomposition/api.yaml +2 -2
  65. package/autopm/.claude/templates/issue-decomposition/auth.yaml +4 -4
  66. package/autopm/.claude/templates/issue-decomposition/crud.yaml +3 -3
  67. package/autopm/.claude/templates/issue-decomposition/default.yaml +1 -1
  68. package/autopm/.claude/templates/issue-decomposition/ui-feature.yaml +2 -2
  69. package/bin/autopm.js +25 -0
  70. package/package.json +1 -2
  71. package/lib/agentExecutor.js.deprecated +0 -101
  72. package/lib/azure/cache.js +0 -80
  73. package/lib/azure/client.js +0 -77
  74. package/lib/azure/formatter.js +0 -177
  75. package/lib/commandHelpers.js +0 -177
  76. package/lib/context/manager.js +0 -290
  77. package/lib/documentation/manager.js +0 -528
  78. package/lib/github/workflow-manager.js +0 -546
  79. package/lib/helpers/azure-batch-api.js +0 -133
  80. package/lib/helpers/azure-cache-manager.js +0 -287
  81. package/lib/helpers/azure-parallel-processor.js +0 -158
  82. package/lib/helpers/azure-work-item-create.js +0 -278
  83. package/lib/helpers/gh-issue-create.js +0 -250
  84. package/lib/helpers/interactive-prompt.js +0 -336
  85. package/lib/helpers/output-manager.js +0 -335
  86. package/lib/helpers/progress-indicator.js +0 -258
  87. package/lib/performance/benchmarker.js +0 -429
  88. package/lib/pm/epic-decomposer.js +0 -273
  89. package/lib/pm/epic-syncer.js +0 -221
  90. package/lib/prdMetadata.js +0 -270
  91. package/lib/providers/azure/index.js +0 -234
  92. package/lib/providers/factory.js +0 -87
  93. package/lib/providers/github/index.js +0 -204
  94. package/lib/providers/interface.js +0 -73
  95. package/lib/python/scaffold-manager.js +0 -576
  96. package/lib/react/scaffold-manager.js +0 -745
  97. package/lib/regression/analyzer.js +0 -578
  98. package/lib/release/manager.js +0 -324
  99. package/lib/tailwind/manager.js +0 -486
  100. package/lib/traefik/manager.js +0 -484
  101. package/lib/utils/colors.js +0 -126
  102. package/lib/utils/config.js +0 -317
  103. package/lib/utils/filesystem.js +0 -316
  104. package/lib/utils/logger.js +0 -135
  105. package/lib/utils/prompts.js +0 -294
  106. package/lib/utils/shell.js +0 -237
  107. package/lib/validators/email-validator.js +0 -337
  108. package/lib/workflow/manager.js +0 -449
@@ -1,576 +0,0 @@
1
- /**
2
- * Python Scaffold Manager
3
- * Centralized Python project scaffolding functionality
4
- */
5
-
6
- const fs = require('fs').promises;
7
- const path = require('path');
8
-
9
- /**
10
- * Configuration
11
- */
12
- const CONFIG = {
13
- defaults: {
14
- port: 8000,
15
- database: 'postgres',
16
- environment: 'development'
17
- }
18
- };
19
-
20
- /**
21
- * Template definitions
22
- */
23
- const TEMPLATES = {
24
- fastapi: {
25
- main: `from fastapi import FastAPI
26
- from fastapi.middleware.cors import CORSMiddleware
27
-
28
- app = FastAPI(title="API", version="1.0.0")
29
-
30
- # Configure CORS
31
- app.add_middleware(
32
- CORSMiddleware,
33
- allow_origins=["*"],
34
- allow_credentials=True,
35
- allow_methods=["*"],
36
- allow_headers=["*"],
37
- )
38
-
39
- @app.get("/")
40
- def read_root():
41
- return {"message": "Welcome to FastAPI"}
42
-
43
- @app.get("/health")
44
- def health_check():
45
- return {"status": "healthy"}
46
- `,
47
- requirements: `fastapi==0.104.1
48
- uvicorn[standard]==0.24.0
49
- pydantic==2.4.2
50
- python-multipart==0.0.6
51
- python-jose[cryptography]==3.3.0
52
- passlib[bcrypt]==1.7.4
53
- sqlalchemy==2.0.23
54
- alembic==1.12.1
55
- psycopg2-binary==2.9.9
56
- redis==5.0.1
57
- celery==5.3.4
58
- pytest==7.4.3
59
- pytest-asyncio==0.21.1
60
- httpx==0.25.1
61
- `
62
- },
63
- flask: {
64
- app: `from flask import Flask, jsonify
65
- from flask_cors import CORS
66
-
67
- app = Flask(__name__)
68
- CORS(app)
69
-
70
- @app.route('/')
71
- def index():
72
- return jsonify({"message": "Welcome to Flask"})
73
-
74
- @app.route('/health')
75
- def health():
76
- return jsonify({"status": "healthy"})
77
-
78
- if __name__ == '__main__':
79
- app.run(debug=True, host='0.0.0.0', port=5000)
80
- `,
81
- requirements: `flask==3.0.0
82
- flask-cors==4.0.0
83
- flask-sqlalchemy==3.1.1
84
- flask-migrate==4.0.5
85
- flask-jwt-extended==4.5.3
86
- python-dotenv==1.0.0
87
- gunicorn==21.2.0
88
- psycopg2-binary==2.9.9
89
- redis==5.0.1
90
- celery==5.3.4
91
- pytest==7.4.3
92
- pytest-flask==1.3.0
93
- `
94
- }
95
- };
96
-
97
- class PythonScaffoldManager {
98
- constructor(projectRoot = process.cwd()) {
99
- this.projectRoot = projectRoot;
100
- }
101
-
102
- /**
103
- * Creates API project
104
- */
105
- async createAPIProject(framework = 'fastapi', projectName = 'api') {
106
- if (framework === 'fastapi') {
107
- return await this.createFastAPIProject(projectName);
108
- } else if (framework === 'flask') {
109
- return await this.createFlaskProject();
110
- } else {
111
- throw new Error(`Unknown framework: ${framework}`);
112
- }
113
- }
114
-
115
- /**
116
- * Creates FastAPI project
117
- */
118
- async createFastAPIProject(projectName) {
119
- const projectDir = path.join(this.projectRoot, projectName);
120
-
121
- // Create directory structure
122
- await fs.mkdir(projectDir, { recursive: true });
123
- await fs.mkdir(path.join(projectDir, 'app'), { recursive: true });
124
- await fs.mkdir(path.join(projectDir, 'app', 'api'), { recursive: true });
125
- await fs.mkdir(path.join(projectDir, 'app', 'core'), { recursive: true });
126
- await fs.mkdir(path.join(projectDir, 'app', 'models'), { recursive: true });
127
-
128
- // Create main.py
129
- await fs.writeFile(path.join(projectDir, 'main.py'), TEMPLATES.fastapi.main);
130
-
131
- // Create __init__.py files
132
- await fs.writeFile(path.join(projectDir, 'app', '__init__.py'), '');
133
- await fs.writeFile(path.join(projectDir, 'app', 'api', '__init__.py'), '');
134
- await fs.writeFile(path.join(projectDir, 'app', 'core', '__init__.py'), '');
135
- await fs.writeFile(path.join(projectDir, 'app', 'models', '__init__.py'), '');
136
-
137
- // Create requirements.txt
138
- await fs.writeFile(
139
- path.join(this.projectRoot, 'requirements.txt'),
140
- TEMPLATES.fastapi.requirements
141
- );
142
-
143
- return {
144
- projectName,
145
- framework: 'fastapi',
146
- mainFile: `${projectName}/main.py`,
147
- structure: ['app/api', 'app/core', 'app/models']
148
- };
149
- }
150
-
151
- /**
152
- * Creates Flask project
153
- */
154
- async createFlaskProject() {
155
- // Create directory structure
156
- await fs.mkdir(path.join(this.projectRoot, 'templates'), { recursive: true });
157
- await fs.mkdir(path.join(this.projectRoot, 'static'), { recursive: true });
158
- await fs.mkdir(path.join(this.projectRoot, 'static', 'css'), { recursive: true });
159
- await fs.mkdir(path.join(this.projectRoot, 'static', 'js'), { recursive: true });
160
-
161
- // Create app.py
162
- await fs.writeFile(
163
- path.join(this.projectRoot, 'app.py'),
164
- TEMPLATES.flask.app
165
- );
166
-
167
- // Create requirements.txt
168
- await fs.writeFile(
169
- path.join(this.projectRoot, 'requirements.txt'),
170
- TEMPLATES.flask.requirements
171
- );
172
-
173
- return {
174
- framework: 'flask',
175
- mainFile: 'app.py',
176
- directories: ['templates/', 'static/']
177
- };
178
- }
179
-
180
- /**
181
- * Creates database models
182
- */
183
- async createModels(database = 'postgres') {
184
- await fs.mkdir(path.join(this.projectRoot, 'models'), { recursive: true });
185
-
186
- // Base model
187
- const baseModel = `from sqlalchemy import Column, Integer, DateTime, func
188
- from sqlalchemy.ext.declarative import declarative_base
189
-
190
- Base = declarative_base()
191
-
192
- class BaseModel(Base):
193
- __abstract__ = True
194
-
195
- id = Column(Integer, primary_key=True, index=True)
196
- created_at = Column(DateTime(timezone=True), server_default=func.now())
197
- updated_at = Column(DateTime(timezone=True), onupdate=func.now())
198
- `;
199
-
200
- // User model
201
- const userModel = `from sqlalchemy import Column, String, Boolean
202
- from .base import BaseModel
203
-
204
- class User(BaseModel):
205
- __tablename__ = "users"
206
-
207
- email = Column(String, unique=True, index=True, nullable=False)
208
- username = Column(String, unique=True, index=True, nullable=False)
209
- hashed_password = Column(String, nullable=False)
210
- is_active = Column(Boolean, default=True)
211
- is_superuser = Column(Boolean, default=False)
212
- `;
213
-
214
- // Database configuration
215
- const dbConfig = `from sqlalchemy import create_engine
216
- from sqlalchemy.orm import sessionmaker
217
-
218
- DATABASE_URL = "${database}://user:password@localhost/dbname"
219
-
220
- engine = create_engine(DATABASE_URL)
221
- SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
222
-
223
- def get_db():
224
- db = SessionLocal()
225
- try:
226
- yield db
227
- finally:
228
- db.close()
229
- `;
230
-
231
- await fs.writeFile(path.join(this.projectRoot, 'models', '__init__.py'), '');
232
- await fs.writeFile(path.join(this.projectRoot, 'models', 'base.py'), baseModel);
233
- await fs.writeFile(path.join(this.projectRoot, 'models', 'user.py'), userModel);
234
- await fs.writeFile(path.join(this.projectRoot, 'models', 'database.py'), dbConfig);
235
-
236
- return {
237
- database,
238
- models: ['base.py', 'user.py'],
239
- config: 'database.py'
240
- };
241
- }
242
-
243
- /**
244
- * Creates API routes
245
- */
246
- async createRoutes(resource = 'items') {
247
- await fs.mkdir(path.join(this.projectRoot, 'routes'), { recursive: true });
248
-
249
- const routeTemplate = `from fastapi import APIRouter, Depends, HTTPException
250
- from sqlalchemy.orm import Session
251
- from typing import List
252
-
253
- router = APIRouter(prefix="/${resource}", tags=["${resource}"])
254
-
255
- @router.get("/", response_model=List[dict])
256
- def get_${resource}():
257
- """Get all ${resource}"""
258
- return [{"id": 1, "name": "Example"}]
259
-
260
- @router.get("/{id}", response_model=dict)
261
- def get_${resource.slice(0, -1)}(id: int):
262
- """Get a specific ${resource.slice(0, -1)}"""
263
- return {"id": id, "name": "Example"}
264
-
265
- @router.post("/", response_model=dict)
266
- def create_${resource.slice(0, -1)}(data: dict):
267
- """Create a new ${resource.slice(0, -1)}"""
268
- return {"id": 1, **data}
269
-
270
- @router.put("/{id}", response_model=dict)
271
- def update_${resource.slice(0, -1)}(id: int, data: dict):
272
- """Update a ${resource.slice(0, -1)}"""
273
- return {"id": id, **data}
274
-
275
- @router.delete("/{id}")
276
- def delete_${resource.slice(0, -1)}(id: int):
277
- """Delete a ${resource.slice(0, -1)}"""
278
- return {"message": "Deleted successfully"}
279
- `;
280
-
281
- await fs.writeFile(path.join(this.projectRoot, 'routes', '__init__.py'), '');
282
- await fs.writeFile(
283
- path.join(this.projectRoot, 'routes', `${resource}.py`),
284
- routeTemplate
285
- );
286
-
287
- return {
288
- resource,
289
- file: `routes/${resource}.py`,
290
- endpoints: ['GET', 'POST', 'PUT', 'DELETE']
291
- };
292
- }
293
-
294
- /**
295
- * Adds authentication
296
- */
297
- async addAuthentication(authType = 'jwt') {
298
- await fs.mkdir(path.join(this.projectRoot, 'auth'), { recursive: true });
299
-
300
- const authInit = `from .auth import *
301
- from .jwt import *
302
- `;
303
-
304
- const jwtAuth = `from datetime import datetime, timedelta
305
- from typing import Optional
306
- from jose import JWTError, jwt
307
- from passlib.context import CryptContext
308
-
309
- SECRET_KEY = "your-secret-key-here"
310
- ALGORITHM = "HS256"
311
- ACCESS_TOKEN_EXPIRE_MINUTES = 30
312
-
313
- pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
314
-
315
- def verify_password(plain_password, hashed_password):
316
- return pwd_context.verify(plain_password, hashed_password)
317
-
318
- def get_password_hash(password):
319
- return pwd_context.hash(password)
320
-
321
- def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
322
- to_encode = data.copy()
323
- if expires_delta:
324
- expire = datetime.utcnow() + expires_delta
325
- else:
326
- expire = datetime.utcnow() + timedelta(minutes=15)
327
- to_encode.update({"exp": expire})
328
- encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
329
- return encoded_jwt
330
-
331
- def decode_token(token: str):
332
- try:
333
- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
334
- return payload
335
- except JWTError:
336
- return None
337
- `;
338
-
339
- await fs.writeFile(path.join(this.projectRoot, 'auth', '__init__.py'), authInit);
340
- await fs.writeFile(path.join(this.projectRoot, 'auth', 'jwt.py'), jwtAuth);
341
-
342
- return {
343
- type: authType,
344
- module: 'auth/',
345
- functions: ['verify_password', 'create_access_token', 'decode_token']
346
- };
347
- }
348
-
349
- /**
350
- * Generates Docker configuration
351
- */
352
- async generateDockerConfig(port = CONFIG.defaults.port) {
353
- const dockerfile = `FROM python:3.11-slim
354
-
355
- WORKDIR /app
356
-
357
- # Install system dependencies
358
- RUN apt-get update && apt-get install -y \\
359
- gcc \\
360
- && rm -rf /var/lib/apt/lists/*
361
-
362
- # Copy requirements first for better caching
363
- COPY requirements.txt .
364
- RUN pip install --no-cache-dir -r requirements.txt
365
-
366
- # Copy application code
367
- COPY . .
368
-
369
- # Expose port
370
- EXPOSE ${port}
371
-
372
- # Run the application
373
- CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "${port}"]
374
- `;
375
-
376
- const dockerCompose = `version: '3.8'
377
-
378
- services:
379
- api:
380
- build: .
381
- ports:
382
- - "${port}:${port}"
383
- environment:
384
- - DATABASE_URL=postgresql://user:password@db:5432/dbname
385
- - REDIS_URL=redis://redis:6379
386
- depends_on:
387
- - db
388
- - redis
389
- volumes:
390
- - .:/app
391
- command: uvicorn main:app --reload --host 0.0.0.0 --port ${port}
392
-
393
- db:
394
- image: postgres:15
395
- environment:
396
- - POSTGRES_USER=user
397
- - POSTGRES_PASSWORD=password
398
- - POSTGRES_DB=dbname
399
- volumes:
400
- - postgres_data:/var/lib/postgresql/data
401
- ports:
402
- - "5432:5432"
403
-
404
- redis:
405
- image: redis:7
406
- ports:
407
- - "6379:6379"
408
-
409
- volumes:
410
- postgres_data:
411
- `;
412
-
413
- await fs.writeFile(path.join(this.projectRoot, 'Dockerfile'), dockerfile);
414
- await fs.writeFile(path.join(this.projectRoot, 'docker-compose.yml'), dockerCompose);
415
-
416
- return {
417
- dockerfile: 'Dockerfile',
418
- compose: 'docker-compose.yml',
419
- port,
420
- services: ['api', 'db', 'redis']
421
- };
422
- }
423
-
424
- /**
425
- * Creates environment configuration
426
- */
427
- async createEnvironmentConfig(env = CONFIG.defaults.environment) {
428
- const envConfig = `# Environment
429
- ENV=${env}
430
- DEBUG=${env === 'development' ? 'true' : 'false'}
431
-
432
- # Application
433
- APP_NAME=Python API
434
- APP_VERSION=1.0.0
435
- SECRET_KEY=your-secret-key-here-change-in-production
436
-
437
- # Database
438
- DATABASE_URL=postgresql://user:password@localhost:5432/dbname
439
- DATABASE_POOL_SIZE=5
440
- DATABASE_MAX_OVERFLOW=10
441
-
442
- # Redis
443
- REDIS_URL=redis://localhost:6379/0
444
-
445
- # JWT
446
- JWT_SECRET_KEY=your-jwt-secret-key
447
- JWT_ALGORITHM=HS256
448
- JWT_EXPIRATION_MINUTES=30
449
-
450
- # CORS
451
- CORS_ORIGINS=http://localhost:3000,http://localhost:8080
452
-
453
- # Logging
454
- LOG_LEVEL=${env === 'development' ? 'DEBUG' : 'INFO'}
455
- `;
456
-
457
- const configLoader = `import os
458
- from dotenv import load_dotenv
459
-
460
- # Load environment variables
461
- load_dotenv(f".env.{os.getenv('ENV', 'development')}")
462
-
463
- class Settings:
464
- # Environment
465
- ENV: str = os.getenv("ENV", "development")
466
- DEBUG: bool = os.getenv("DEBUG", "false").lower() == "true"
467
-
468
- # Application
469
- APP_NAME: str = os.getenv("APP_NAME", "API")
470
- APP_VERSION: str = os.getenv("APP_VERSION", "1.0.0")
471
- SECRET_KEY: str = os.getenv("SECRET_KEY", "")
472
-
473
- # Database
474
- DATABASE_URL: str = os.getenv("DATABASE_URL", "")
475
-
476
- # Redis
477
- REDIS_URL: str = os.getenv("REDIS_URL", "")
478
-
479
- # JWT
480
- JWT_SECRET_KEY: str = os.getenv("JWT_SECRET_KEY", "")
481
- JWT_ALGORITHM: str = os.getenv("JWT_ALGORITHM", "HS256")
482
- JWT_EXPIRATION_MINUTES: int = int(os.getenv("JWT_EXPIRATION_MINUTES", "30"))
483
-
484
- settings = Settings()
485
- `;
486
-
487
- await fs.writeFile(path.join(this.projectRoot, `.env.${env}`), envConfig);
488
- await fs.writeFile(path.join(this.projectRoot, 'config.py'), configLoader);
489
-
490
- return {
491
- environment: env,
492
- configFile: `.env.${env}`,
493
- loader: 'config.py'
494
- };
495
- }
496
-
497
- /**
498
- * Sets up testing framework
499
- */
500
- async setupTesting(framework = 'pytest') {
501
- await fs.mkdir(path.join(this.projectRoot, 'tests'), { recursive: true });
502
- await fs.mkdir(path.join(this.projectRoot, 'tests', 'unit'), { recursive: true });
503
- await fs.mkdir(path.join(this.projectRoot, 'tests', 'integration'), { recursive: true });
504
-
505
- // Create pytest.ini
506
- const pytestConfig = `[pytest]
507
- testpaths = tests
508
- python_files = test_*.py
509
- python_classes = Test*
510
- python_functions = test_*
511
- addopts = -v --tb=short --strict-markers --cov=app --cov-report=term-missing
512
- markers =
513
- unit: Unit tests
514
- integration: Integration tests
515
- slow: Slow tests
516
- `;
517
-
518
- // Create conftest.py
519
- const conftest = `import pytest
520
- from fastapi.testclient import TestClient
521
- from sqlalchemy import create_engine
522
- from sqlalchemy.orm import sessionmaker
523
-
524
- @pytest.fixture
525
- def client():
526
- from main import app
527
- return TestClient(app)
528
-
529
- @pytest.fixture
530
- def db_session():
531
- # Create test database session
532
- engine = create_engine("sqlite:///:memory:")
533
- SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
534
- session = SessionLocal()
535
- yield session
536
- session.close()
537
- `;
538
-
539
- // Sample test
540
- const sampleTest = `import pytest
541
-
542
- def test_health_check(client):
543
- response = client.get("/health")
544
- assert response.status_code == 200
545
- assert response.json() == {"status": "healthy"}
546
-
547
- def test_root(client):
548
- response = client.get("/")
549
- assert response.status_code == 200
550
- assert "message" in response.json()
551
-
552
- @pytest.mark.unit
553
- def test_example_unit():
554
- assert 1 + 1 == 2
555
-
556
- @pytest.mark.integration
557
- def test_example_integration(db_session):
558
- # Test with database
559
- assert db_session is not None
560
- `;
561
-
562
- await fs.writeFile(path.join(this.projectRoot, 'pytest.ini'), pytestConfig);
563
- await fs.writeFile(path.join(this.projectRoot, 'tests', '__init__.py'), '');
564
- await fs.writeFile(path.join(this.projectRoot, 'tests', 'conftest.py'), conftest);
565
- await fs.writeFile(path.join(this.projectRoot, 'tests', 'test_main.py'), sampleTest);
566
-
567
- return {
568
- framework,
569
- config: 'pytest.ini',
570
- testsDir: 'tests/',
571
- fixtures: 'conftest.py'
572
- };
573
- }
574
- }
575
-
576
- module.exports = PythonScaffoldManager;