claude-autopm 1.18.0 → 1.20.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 (75) hide show
  1. package/README.md +159 -0
  2. package/autopm/.claude/agents/core/mcp-manager.md +1 -1
  3. package/autopm/.claude/commands/pm/context.md +11 -0
  4. package/autopm/.claude/commands/pm/epic-decompose.md +25 -2
  5. package/autopm/.claude/commands/pm/epic-oneshot.md +13 -0
  6. package/autopm/.claude/commands/pm/epic-start.md +19 -0
  7. package/autopm/.claude/commands/pm/epic-sync-modular.md +10 -10
  8. package/autopm/.claude/commands/pm/epic-sync.md +14 -14
  9. package/autopm/.claude/commands/pm/issue-start.md +50 -5
  10. package/autopm/.claude/commands/pm/issue-sync.md +15 -15
  11. package/autopm/.claude/commands/pm/what-next.md +11 -0
  12. package/autopm/.claude/mcp/MCP-REGISTRY.md +1 -1
  13. package/autopm/.claude/scripts/azure/active-work.js +2 -2
  14. package/autopm/.claude/scripts/azure/blocked.js +13 -13
  15. package/autopm/.claude/scripts/azure/daily.js +1 -1
  16. package/autopm/.claude/scripts/azure/dashboard.js +1 -1
  17. package/autopm/.claude/scripts/azure/feature-list.js +2 -2
  18. package/autopm/.claude/scripts/azure/feature-status.js +1 -1
  19. package/autopm/.claude/scripts/azure/next-task.js +1 -1
  20. package/autopm/.claude/scripts/azure/search.js +1 -1
  21. package/autopm/.claude/scripts/azure/setup.js +15 -15
  22. package/autopm/.claude/scripts/azure/sprint-report.js +2 -2
  23. package/autopm/.claude/scripts/azure/sync.js +1 -1
  24. package/autopm/.claude/scripts/azure/us-list.js +1 -1
  25. package/autopm/.claude/scripts/azure/us-status.js +1 -1
  26. package/autopm/.claude/scripts/azure/validate.js +13 -13
  27. package/autopm/.claude/scripts/lib/frontmatter-utils.sh +42 -7
  28. package/autopm/.claude/scripts/lib/logging-utils.sh +20 -16
  29. package/autopm/.claude/scripts/lib/validation-utils.sh +1 -1
  30. package/autopm/.claude/scripts/pm/context.js +338 -0
  31. package/autopm/.claude/scripts/pm/issue-sync/format-comment.sh +3 -3
  32. package/autopm/.claude/scripts/pm/lib/README.md +85 -0
  33. package/autopm/.claude/scripts/pm/lib/logger.js +78 -0
  34. package/autopm/.claude/scripts/pm/next.js +25 -1
  35. package/autopm/.claude/scripts/pm/what-next.js +660 -0
  36. package/bin/autopm.js +25 -0
  37. package/package.json +1 -1
  38. package/lib/agentExecutor.js.deprecated +0 -101
  39. package/lib/azure/cache.js +0 -80
  40. package/lib/azure/client.js +0 -77
  41. package/lib/azure/formatter.js +0 -177
  42. package/lib/commandHelpers.js +0 -177
  43. package/lib/context/manager.js +0 -290
  44. package/lib/documentation/manager.js +0 -528
  45. package/lib/github/workflow-manager.js +0 -546
  46. package/lib/helpers/azure-batch-api.js +0 -133
  47. package/lib/helpers/azure-cache-manager.js +0 -287
  48. package/lib/helpers/azure-parallel-processor.js +0 -158
  49. package/lib/helpers/azure-work-item-create.js +0 -278
  50. package/lib/helpers/gh-issue-create.js +0 -250
  51. package/lib/helpers/interactive-prompt.js +0 -336
  52. package/lib/helpers/output-manager.js +0 -335
  53. package/lib/helpers/progress-indicator.js +0 -258
  54. package/lib/performance/benchmarker.js +0 -429
  55. package/lib/pm/epic-decomposer.js +0 -273
  56. package/lib/pm/epic-syncer.js +0 -221
  57. package/lib/prdMetadata.js +0 -270
  58. package/lib/providers/azure/index.js +0 -234
  59. package/lib/providers/factory.js +0 -87
  60. package/lib/providers/github/index.js +0 -204
  61. package/lib/providers/interface.js +0 -73
  62. package/lib/python/scaffold-manager.js +0 -576
  63. package/lib/react/scaffold-manager.js +0 -745
  64. package/lib/regression/analyzer.js +0 -578
  65. package/lib/release/manager.js +0 -324
  66. package/lib/tailwind/manager.js +0 -486
  67. package/lib/traefik/manager.js +0 -484
  68. package/lib/utils/colors.js +0 -126
  69. package/lib/utils/config.js +0 -317
  70. package/lib/utils/filesystem.js +0 -316
  71. package/lib/utils/logger.js +0 -135
  72. package/lib/utils/prompts.js +0 -294
  73. package/lib/utils/shell.js +0 -237
  74. package/lib/validators/email-validator.js +0 -337
  75. 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;