aegis-stack 0.1.0__py3-none-any.whl
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.
Potentially problematic release.
This version of aegis-stack might be problematic. Click here for more details.
- aegis/__init__.py +5 -0
- aegis/__main__.py +374 -0
- aegis/core/CLAUDE.md +365 -0
- aegis/core/__init__.py +6 -0
- aegis/core/components.py +115 -0
- aegis/core/dependency_resolver.py +119 -0
- aegis/core/template_generator.py +163 -0
- aegis/templates/CLAUDE.md +306 -0
- aegis/templates/cookiecutter-aegis-project/cookiecutter.json +27 -0
- aegis/templates/cookiecutter-aegis-project/hooks/post_gen_project.py +172 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.dockerignore +71 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.env.example.j2 +70 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.gitignore +127 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/Dockerfile +53 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/Makefile +211 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/README.md.j2 +196 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/__init__.py +5 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/__init__.py +6 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/health.py +321 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/load_test.py +638 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/main.py +41 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/__init__.py +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/__init__.py +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/health.py +134 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/models.py.j2 +247 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/routing.py.j2 +14 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/tasks.py.j2 +596 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/hooks.py +133 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/main.py +16 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/middleware/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/middleware/cors.py +20 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/shutdown/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/shutdown/cleanup.py +14 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/startup/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/startup/component_health.py.j2 +190 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/__init__.py +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/core/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/core/theme.py +46 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/main.py +687 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/scheduler/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/scheduler/main.py +138 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/CLAUDE.md +213 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/__init__.py +6 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/constants.py.j2 +30 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/pools.py +78 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/load_test.py +48 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/media.py +41 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/system.py +36 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/registry.py +139 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/__init__.py +119 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/load_tasks.py +526 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/simple_system_tasks.py +32 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/system_tasks.py +279 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/config.py.j2 +119 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/constants.py +60 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/db.py +67 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/log.py +85 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/entrypoints/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/entrypoints/webserver.py +40 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/entrypoints/{% if cookiecutter.include_scheduler == /"yes/" %}scheduler.py{% endif %}" +21 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/integrations/__init__.py +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/integrations/main.py +61 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/py.typed +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/load_test.py +661 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/load_test_models.py +269 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/shared/__init__.py +15 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/shared/models.py +26 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/__init__.py +52 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/alerts.py +94 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/health.py.j2 +1105 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/models.py +169 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/ui.py +52 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docker-compose.yml.j2 +195 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/api.md +191 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/components/scheduler.md +414 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/development.md +215 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/health.md +240 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/javascripts/mermaid-config.js +62 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/stylesheets/mermaid.css +95 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/mkdocs.yml.j2 +62 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/pyproject.toml.j2 +156 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/entrypoint.sh +87 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/entrypoint.sh.j2 +104 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/gen_docs.py +16 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_health_endpoints.py.j2 +239 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/components/test_scheduler.py +76 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/conftest.py.j2 +81 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_component_integration.py.j2 +376 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_health_logic.py.j2 +633 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_load_test_models.py +665 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_load_test_service.py +602 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_system_service.py +96 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_worker_health_registration.py.j2 +224 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/test_core.py +50 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/uv.lock +1673 -0
- aegis_stack-0.1.0.dist-info/METADATA +114 -0
- aegis_stack-0.1.0.dist-info/RECORD +103 -0
- aegis_stack-0.1.0.dist-info/WHEEL +4 -0
- aegis_stack-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# Health Monitoring
|
|
2
|
+
|
|
3
|
+
{{ cookiecutter.project_name }} includes comprehensive health monitoring capabilities through both API endpoints and CLI commands.
|
|
4
|
+
|
|
5
|
+
## Health Check Endpoints
|
|
6
|
+
|
|
7
|
+
### Basic Health Check
|
|
8
|
+
- **URL**: `GET /health/`
|
|
9
|
+
- **Purpose**: Quick health status check
|
|
10
|
+
- **Response Time**: < 100ms
|
|
11
|
+
|
|
12
|
+
### Detailed Health Check
|
|
13
|
+
- **URL**: `GET /health/detailed`
|
|
14
|
+
- **Purpose**: Comprehensive system health with metrics
|
|
15
|
+
- **Response Time**: < 500ms
|
|
16
|
+
|
|
17
|
+
## CLI Health Commands
|
|
18
|
+
|
|
19
|
+
{{ cookiecutter.project_name }} provides a built-in CLI for health monitoring:
|
|
20
|
+
|
|
21
|
+
### Basic Health Check
|
|
22
|
+
```bash
|
|
23
|
+
{{ cookiecutter.project_slug }} health status
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Output:**
|
|
27
|
+
```
|
|
28
|
+
✅ {{ cookiecutter.project_name }} - System Status: HEALTHY
|
|
29
|
+
|
|
30
|
+
🖥️ System Health:
|
|
31
|
+
• CPU Usage: 15.2%
|
|
32
|
+
• Memory Usage: 45.8%
|
|
33
|
+
• Disk Usage: 32.1%
|
|
34
|
+
• Response Time: 2.1ms{% if cookiecutter.include_scheduler == "yes" %}
|
|
35
|
+
|
|
36
|
+
⏰ Scheduler Health:
|
|
37
|
+
• Status: HEALTHY
|
|
38
|
+
• Active Jobs: 2
|
|
39
|
+
• Next Run: 2024-01-01 02:00:00
|
|
40
|
+
• Response Time: 1.5ms{% endif %}
|
|
41
|
+
|
|
42
|
+
🔍 Overall Health: 98.5%
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Detailed Health Check
|
|
46
|
+
```bash
|
|
47
|
+
{{ cookiecutter.project_slug }} health status --detailed
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Shows comprehensive system information including:
|
|
51
|
+
- Component-level health status
|
|
52
|
+
- System resource utilization
|
|
53
|
+
- Response time metrics
|
|
54
|
+
- Uptime information
|
|
55
|
+
|
|
56
|
+
### JSON Output
|
|
57
|
+
```bash
|
|
58
|
+
{{ cookiecutter.project_slug }} health status --json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Returns structured JSON for integration with monitoring systems:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"healthy": true,
|
|
66
|
+
"status": "healthy",
|
|
67
|
+
"components": {
|
|
68
|
+
"system": {
|
|
69
|
+
"status": "healthy",
|
|
70
|
+
"cpu_percent": 15.2,
|
|
71
|
+
"memory_percent": 45.8,
|
|
72
|
+
"disk_percent": 32.1,
|
|
73
|
+
"response_time_ms": 2.1
|
|
74
|
+
}{% if cookiecutter.include_scheduler == "yes" %},
|
|
75
|
+
"scheduler": {
|
|
76
|
+
"status": "healthy",
|
|
77
|
+
"active_jobs": 2,
|
|
78
|
+
"next_run": "2024-01-01T02:00:00Z",
|
|
79
|
+
"response_time_ms": 1.5
|
|
80
|
+
}{% endif %}
|
|
81
|
+
},
|
|
82
|
+
"timestamp": "2024-01-01T00:00:00Z",
|
|
83
|
+
"uptime_seconds": 3600,
|
|
84
|
+
"health_percentage": 98.5
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Health Probe
|
|
89
|
+
```bash
|
|
90
|
+
{{ cookiecutter.project_slug }} health probe
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Returns simple healthy/unhealthy status for use in scripts and monitoring.
|
|
94
|
+
|
|
95
|
+
## Using Health Checks in Development
|
|
96
|
+
|
|
97
|
+
### Make Commands
|
|
98
|
+
Convenient make targets are available:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
make health # Basic health check
|
|
102
|
+
make health-detailed # Detailed health information
|
|
103
|
+
make health-json # JSON health output
|
|
104
|
+
make health-probe # Health probe for monitoring
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Health Check Components
|
|
108
|
+
|
|
109
|
+
### System Health
|
|
110
|
+
Monitors core system resources:
|
|
111
|
+
|
|
112
|
+
- **CPU Usage**: Current CPU utilization percentage
|
|
113
|
+
- **Memory Usage**: RAM utilization percentage
|
|
114
|
+
- **Disk Usage**: Disk space utilization percentage
|
|
115
|
+
- **Response Time**: Health check response time{% if cookiecutter.include_scheduler == "yes" %}
|
|
116
|
+
|
|
117
|
+
### Scheduler Health
|
|
118
|
+
Monitors the background task scheduler:
|
|
119
|
+
|
|
120
|
+
- **Scheduler Status**: Running/stopped status
|
|
121
|
+
- **Active Jobs**: Number of currently scheduled jobs
|
|
122
|
+
- **Next Run**: When the next job will execute
|
|
123
|
+
- **Job History**: Recent job execution status{% endif %}
|
|
124
|
+
|
|
125
|
+
## Integration with Monitoring Systems
|
|
126
|
+
|
|
127
|
+
### Prometheus Metrics
|
|
128
|
+
To add Prometheus metrics:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
# app/components/backend/middleware/prometheus.py
|
|
132
|
+
from prometheus_client import Counter, Histogram, generate_latest
|
|
133
|
+
from fastapi import Request, Response
|
|
134
|
+
|
|
135
|
+
REQUEST_COUNT = Counter('http_requests_total', 'Total HTTP requests', ['method', 'endpoint'])
|
|
136
|
+
REQUEST_DURATION = Histogram('http_request_duration_seconds', 'HTTP request duration')
|
|
137
|
+
|
|
138
|
+
@app.middleware("http")
|
|
139
|
+
async def prometheus_middleware(request: Request, call_next):
|
|
140
|
+
start_time = time.time()
|
|
141
|
+
response = await call_next(request)
|
|
142
|
+
|
|
143
|
+
REQUEST_COUNT.labels(method=request.method, endpoint=request.url.path).inc()
|
|
144
|
+
REQUEST_DURATION.observe(time.time() - start_time)
|
|
145
|
+
|
|
146
|
+
return response
|
|
147
|
+
|
|
148
|
+
@app.get("/metrics")
|
|
149
|
+
async def metrics():
|
|
150
|
+
return Response(generate_latest(), media_type="text/plain")
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### External Health Checks
|
|
154
|
+
The health endpoints can be monitored by external systems:
|
|
155
|
+
|
|
156
|
+
- **Uptime monitoring**: Ping `/health/` endpoint
|
|
157
|
+
- **Performance monitoring**: Track `/health/detailed` response times
|
|
158
|
+
- **Alerting**: Monitor health percentage thresholds
|
|
159
|
+
|
|
160
|
+
### Docker Health Checks
|
|
161
|
+
The Docker container includes built-in health checks:
|
|
162
|
+
|
|
163
|
+
```dockerfile
|
|
164
|
+
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
|
|
165
|
+
CMD curl -f http://localhost:8000/health || exit 1
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Troubleshooting Health Issues
|
|
169
|
+
|
|
170
|
+
### Common Issues
|
|
171
|
+
|
|
172
|
+
**Health check timeouts:**
|
|
173
|
+
- Check if application is running on expected port
|
|
174
|
+
- Verify no firewall blocking connections
|
|
175
|
+
- Check application logs for startup errors
|
|
176
|
+
|
|
177
|
+
**High resource usage:**
|
|
178
|
+
- Monitor CPU/memory usage over time
|
|
179
|
+
- Check for memory leaks in long-running processes
|
|
180
|
+
- Review recent code changes{% if cookiecutter.include_scheduler == "yes" %}
|
|
181
|
+
|
|
182
|
+
**Scheduler issues:**
|
|
183
|
+
- Check scheduler logs for job failures
|
|
184
|
+
- Verify scheduled job configurations
|
|
185
|
+
- Monitor job execution times{% endif %}
|
|
186
|
+
|
|
187
|
+
### Debug Commands
|
|
188
|
+
```bash
|
|
189
|
+
# Check if service is running
|
|
190
|
+
curl http://localhost:8000/health/
|
|
191
|
+
|
|
192
|
+
# Check application logs
|
|
193
|
+
docker compose logs -f
|
|
194
|
+
|
|
195
|
+
# Monitor resource usage
|
|
196
|
+
docker stats
|
|
197
|
+
|
|
198
|
+
# Test CLI connectivity
|
|
199
|
+
{{ cookiecutter.project_slug }} health check --debug
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Health Check Best Practices
|
|
203
|
+
|
|
204
|
+
1. **Regular Monitoring**: Set up automated health checks every 30-60 seconds
|
|
205
|
+
2. **Alerting Thresholds**: Alert when health percentage drops below 95%
|
|
206
|
+
3. **Response Time Monitoring**: Alert on health check response times > 1 second
|
|
207
|
+
4. **Component-Level Monitoring**: Monitor individual components, not just overall health
|
|
208
|
+
5. **Historical Tracking**: Store health metrics for trend analysis
|
|
209
|
+
|
|
210
|
+
## Customizing Health Checks
|
|
211
|
+
|
|
212
|
+
To add custom health checks, extend the system service:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
# app/services/system_service.py
|
|
216
|
+
async def check_database_health() -> ComponentHealth:
|
|
217
|
+
"""Check database connectivity."""
|
|
218
|
+
try:
|
|
219
|
+
# Perform database ping
|
|
220
|
+
start_time = datetime.utcnow()
|
|
221
|
+
# ... database check logic ...
|
|
222
|
+
end_time = datetime.utcnow()
|
|
223
|
+
|
|
224
|
+
return ComponentHealth(
|
|
225
|
+
status="healthy",
|
|
226
|
+
details={
|
|
227
|
+
"connection_pool": "active",
|
|
228
|
+
"query_response_ms": (end_time - start_time).total_seconds() * 1000
|
|
229
|
+
},
|
|
230
|
+
response_time_ms=(end_time - start_time).total_seconds() * 1000
|
|
231
|
+
)
|
|
232
|
+
except Exception as e:
|
|
233
|
+
return ComponentHealth(
|
|
234
|
+
status="unhealthy",
|
|
235
|
+
details={"error": str(e)},
|
|
236
|
+
response_time_ms=0
|
|
237
|
+
)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Then register it in the health check system to have it included in all health reports.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Mermaid configuration for dark/light mode support
|
|
2
|
+
document.addEventListener("DOMContentLoaded", function() {
|
|
3
|
+
// Function to get current theme
|
|
4
|
+
function getCurrentTheme() {
|
|
5
|
+
return document.querySelector('[data-md-color-scheme]').getAttribute('data-md-color-scheme');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Function to configure Mermaid theme
|
|
9
|
+
function configureMermaid() {
|
|
10
|
+
const theme = getCurrentTheme();
|
|
11
|
+
const mermaidTheme = theme === 'slate' ? 'dark' : 'default';
|
|
12
|
+
|
|
13
|
+
mermaid.initialize({
|
|
14
|
+
startOnLoad: true,
|
|
15
|
+
theme: mermaidTheme,
|
|
16
|
+
themeVariables: {
|
|
17
|
+
// Light mode colors
|
|
18
|
+
primaryColor: theme === 'default' ? '#1976d2' : '#64b5f6',
|
|
19
|
+
primaryTextColor: theme === 'default' ? '#000000' : '#ffffff',
|
|
20
|
+
primaryBorderColor: theme === 'default' ? '#1976d2' : '#64b5f6',
|
|
21
|
+
lineColor: theme === 'default' ? '#333333' : '#ffffff',
|
|
22
|
+
secondaryColor: theme === 'default' ? '#e3f2fd' : '#1e1e1e',
|
|
23
|
+
tertiaryColor: theme === 'default' ? '#f5f5f5' : '#2d2d2d',
|
|
24
|
+
background: theme === 'default' ? '#ffffff' : '#1e1e1e',
|
|
25
|
+
mainBkg: theme === 'default' ? '#ffffff' : '#1e1e1e',
|
|
26
|
+
secondBkg: theme === 'default' ? '#f8f9fa' : '#2d2d2d',
|
|
27
|
+
tertiaryBkg: theme === 'default' ? '#e9ecef' : '#404040'
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Re-render all mermaid diagrams
|
|
32
|
+
if (typeof mermaid !== 'undefined') {
|
|
33
|
+
const mermaidElements = document.querySelectorAll('.mermaid');
|
|
34
|
+
mermaidElements.forEach((element, index) => {
|
|
35
|
+
element.removeAttribute('data-processed');
|
|
36
|
+
element.innerHTML = element.getAttribute('data-original') || element.innerHTML;
|
|
37
|
+
if (!element.getAttribute('data-original')) {
|
|
38
|
+
element.setAttribute('data-original', element.innerHTML);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
mermaid.init();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Initial configuration
|
|
46
|
+
configureMermaid();
|
|
47
|
+
|
|
48
|
+
// Listen for theme changes
|
|
49
|
+
const observer = new MutationObserver(function(mutations) {
|
|
50
|
+
mutations.forEach(function(mutation) {
|
|
51
|
+
if (mutation.type === 'attributes' && mutation.attributeName === 'data-md-color-scheme') {
|
|
52
|
+
setTimeout(configureMermaid, 100); // Small delay to ensure theme is applied
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Start observing theme changes
|
|
58
|
+
const target = document.querySelector('[data-md-color-scheme]');
|
|
59
|
+
if (target) {
|
|
60
|
+
observer.observe(target, { attributes: true });
|
|
61
|
+
}
|
|
62
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* Mermaid diagram styling for light and dark modes */
|
|
2
|
+
|
|
3
|
+
/* Base mermaid diagram styling */
|
|
4
|
+
.mermaid {
|
|
5
|
+
text-align: center;
|
|
6
|
+
margin: 1em 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/* Light mode styling */
|
|
10
|
+
[data-md-color-scheme="default"] .mermaid {
|
|
11
|
+
--mermaid-primary-color: #1976d2;
|
|
12
|
+
--mermaid-primary-text-color: #000000;
|
|
13
|
+
--mermaid-primary-border-color: #1976d2;
|
|
14
|
+
--mermaid-line-color: #333333;
|
|
15
|
+
--mermaid-secondary-color: #e3f2fd;
|
|
16
|
+
--mermaid-tertiary-color: #f5f5f5;
|
|
17
|
+
--mermaid-background: #ffffff;
|
|
18
|
+
--mermaid-main-bkg: #ffffff;
|
|
19
|
+
--mermaid-second-bkg: #f8f9fa;
|
|
20
|
+
--mermaid-tertiary-bkg: #e9ecef;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Dark mode styling */
|
|
24
|
+
[data-md-color-scheme="slate"] .mermaid {
|
|
25
|
+
--mermaid-primary-color: #64b5f6;
|
|
26
|
+
--mermaid-primary-text-color: #ffffff;
|
|
27
|
+
--mermaid-primary-border-color: #64b5f6;
|
|
28
|
+
--mermaid-line-color: #ffffff;
|
|
29
|
+
--mermaid-secondary-color: #1e1e1e;
|
|
30
|
+
--mermaid-tertiary-color: #2d2d2d;
|
|
31
|
+
--mermaid-background: #1e1e1e;
|
|
32
|
+
--mermaid-main-bkg: #1e1e1e;
|
|
33
|
+
--mermaid-second-bkg: #2d2d2d;
|
|
34
|
+
--mermaid-tertiary-bkg: #404040;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Ensure mermaid diagrams are visible in dark mode */
|
|
38
|
+
[data-md-color-scheme="slate"] .mermaid svg {
|
|
39
|
+
background: transparent !important;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
[data-md-color-scheme="slate"] .mermaid .node rect,
|
|
43
|
+
[data-md-color-scheme="slate"] .mermaid .node circle,
|
|
44
|
+
[data-md-color-scheme="slate"] .mermaid .node ellipse,
|
|
45
|
+
[data-md-color-scheme="slate"] .mermaid .node polygon {
|
|
46
|
+
fill: var(--mermaid-main-bkg) !important;
|
|
47
|
+
stroke: var(--mermaid-primary-border-color) !important;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
[data-md-color-scheme="slate"] .mermaid .node .label {
|
|
51
|
+
color: var(--mermaid-primary-text-color) !important;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
[data-md-color-scheme="slate"] .mermaid .edgePath .path {
|
|
55
|
+
stroke: var(--mermaid-line-color) !important;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
[data-md-color-scheme="slate"] .mermaid .edgeLabel {
|
|
59
|
+
background-color: var(--mermaid-background) !important;
|
|
60
|
+
color: var(--mermaid-primary-text-color) !important;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* Flowchart specific styling */
|
|
64
|
+
[data-md-color-scheme="slate"] .mermaid .cluster rect {
|
|
65
|
+
fill: var(--mermaid-second-bkg) !important;
|
|
66
|
+
stroke: var(--mermaid-primary-border-color) !important;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
[data-md-color-scheme="slate"] .mermaid .cluster .label {
|
|
70
|
+
color: var(--mermaid-primary-text-color) !important;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Sequence diagram specific styling */
|
|
74
|
+
[data-md-color-scheme="slate"] .mermaid .actor {
|
|
75
|
+
fill: var(--mermaid-main-bkg) !important;
|
|
76
|
+
stroke: var(--mermaid-primary-border-color) !important;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
[data-md-color-scheme="slate"] .mermaid .actor-line {
|
|
80
|
+
stroke: var(--mermaid-line-color) !important;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
[data-md-color-scheme="slate"] .mermaid .messageLine0,
|
|
84
|
+
[data-md-color-scheme="slate"] .mermaid .messageLine1 {
|
|
85
|
+
stroke: var(--mermaid-line-color) !important;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
[data-md-color-scheme="slate"] .mermaid .messageText {
|
|
89
|
+
fill: var(--mermaid-primary-text-color) !important;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
[data-md-color-scheme="slate"] .mermaid .note {
|
|
93
|
+
fill: var(--mermaid-tertiary-bkg) !important;
|
|
94
|
+
stroke: var(--mermaid-primary-border-color) !important;
|
|
95
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# mkdocs.yml
|
|
2
|
+
site_name: {{ cookiecutter.project_name }}
|
|
3
|
+
site_description: {{ cookiecutter.project_description }}
|
|
4
|
+
site_author: {{ cookiecutter.author_name }}
|
|
5
|
+
site_url: https://{{ cookiecutter.github_username }}.github.io/{{ cookiecutter.project_slug }}/
|
|
6
|
+
|
|
7
|
+
theme:
|
|
8
|
+
name: material
|
|
9
|
+
palette:
|
|
10
|
+
# Palette toggle for light vs dark mode
|
|
11
|
+
- scheme: default
|
|
12
|
+
toggle:
|
|
13
|
+
icon: material/brightness-7
|
|
14
|
+
name: Switch to dark mode
|
|
15
|
+
- scheme: slate
|
|
16
|
+
toggle:
|
|
17
|
+
icon: material/brightness-4
|
|
18
|
+
name: Switch to light mode
|
|
19
|
+
features:
|
|
20
|
+
- navigation.tabs
|
|
21
|
+
- navigation.top
|
|
22
|
+
- search.highlight
|
|
23
|
+
- search.suggest
|
|
24
|
+
- content.code.copy
|
|
25
|
+
|
|
26
|
+
# Navigation structure
|
|
27
|
+
nav:
|
|
28
|
+
- Home: index.md
|
|
29
|
+
- Development: development.md
|
|
30
|
+
- API Reference: api.md
|
|
31
|
+
- Health Monitoring: health.md{% if cookiecutter.include_scheduler == "yes" %}
|
|
32
|
+
- Components:
|
|
33
|
+
- Scheduler: components/scheduler.md{% endif %}
|
|
34
|
+
|
|
35
|
+
# Plugins
|
|
36
|
+
plugins:
|
|
37
|
+
- gen-files:
|
|
38
|
+
scripts:
|
|
39
|
+
- scripts/gen_docs.py
|
|
40
|
+
- search
|
|
41
|
+
- mkdocstrings:
|
|
42
|
+
handlers:
|
|
43
|
+
python:
|
|
44
|
+
options:
|
|
45
|
+
show_root_heading: true
|
|
46
|
+
show_source: true
|
|
47
|
+
|
|
48
|
+
# Markdown extensions
|
|
49
|
+
markdown_extensions:
|
|
50
|
+
- pymdownx.superfences:
|
|
51
|
+
custom_fences:
|
|
52
|
+
- name: mermaid
|
|
53
|
+
class: mermaid
|
|
54
|
+
format: !!python/name:pymdownx.superfences.fence_code_format
|
|
55
|
+
|
|
56
|
+
# Additional configuration for Mermaid dark mode support
|
|
57
|
+
extra_javascript:
|
|
58
|
+
- https://unpkg.com/mermaid@10.6.0/dist/mermaid.min.js
|
|
59
|
+
- javascripts/mermaid-config.js
|
|
60
|
+
|
|
61
|
+
extra_css:
|
|
62
|
+
- stylesheets/mermaid.css
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "{{ cookiecutter.project_slug }}"
|
|
3
|
+
version = "{{ cookiecutter.version }}"
|
|
4
|
+
description = "{{ cookiecutter.project_description }}"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">={{ cookiecutter.python_version }}"
|
|
7
|
+
authors = [
|
|
8
|
+
{name = "{{ cookiecutter.author_name }}", email = "{{ cookiecutter.author_email }}"}
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
"fastapi==0.116.1",
|
|
13
|
+
"flet[all]==0.28.3",
|
|
14
|
+
"uvicorn==0.35.0",
|
|
15
|
+
"structlog==25.4.0",
|
|
16
|
+
"pydantic-settings==2.10.1",
|
|
17
|
+
"typer==0.16.0",
|
|
18
|
+
# Pin click to avoid yanked versions (typer dependency)
|
|
19
|
+
"click==8.2.1",
|
|
20
|
+
# Rich CLI formatting
|
|
21
|
+
"rich==14.1.0",
|
|
22
|
+
# HTTP client for CLI API calls
|
|
23
|
+
"httpx==0.28.1",
|
|
24
|
+
# System monitoring
|
|
25
|
+
"psutil==7.0.0",
|
|
26
|
+
{%- if cookiecutter.include_scheduler == "yes" %}
|
|
27
|
+
"apscheduler==3.10.4",
|
|
28
|
+
{%- endif %}
|
|
29
|
+
{%- if cookiecutter.include_redis == "yes" %}
|
|
30
|
+
"redis==5.0.8",
|
|
31
|
+
{%- endif %}
|
|
32
|
+
{%- if cookiecutter.include_worker == "yes" %}
|
|
33
|
+
"arq==0.25.0",
|
|
34
|
+
{%- endif %}
|
|
35
|
+
{%- if cookiecutter.include_database == "yes" %}
|
|
36
|
+
"sqlmodel>=0.0.14",
|
|
37
|
+
"sqlalchemy>=2.0.0",
|
|
38
|
+
"aiosqlite>=0.19.0",
|
|
39
|
+
{%- endif %}
|
|
40
|
+
{%- if cookiecutter.include_cache == "yes" %}
|
|
41
|
+
"redis[hiredis]==5.0.8",
|
|
42
|
+
{%- endif %}
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[project.scripts]
|
|
46
|
+
{{cookiecutter.project_slug}} = "app.cli.main:main"
|
|
47
|
+
|
|
48
|
+
[project.optional-dependencies]
|
|
49
|
+
dev = [
|
|
50
|
+
"pytest==8.4.1",
|
|
51
|
+
"pytest-asyncio==1.1.0",
|
|
52
|
+
"ruff==0.12.7",
|
|
53
|
+
"mypy==1.17.1",
|
|
54
|
+
"types-psutil==7.0.0.20250801",
|
|
55
|
+
"pre-commit==4.2.0",
|
|
56
|
+
"pip-audit==2.9.0",
|
|
57
|
+
{%- if cookiecutter.include_worker == "yes" %}
|
|
58
|
+
# Development auto-reload for workers
|
|
59
|
+
"watchdog==4.0.2",
|
|
60
|
+
{%- endif %}
|
|
61
|
+
]
|
|
62
|
+
docs = [
|
|
63
|
+
"mkdocs==1.6.1",
|
|
64
|
+
"mkdocs-material==9.6.16",
|
|
65
|
+
"mkdocstrings[python]==0.30.0",
|
|
66
|
+
"mkdocs-gen-files==0.5.0",
|
|
67
|
+
"pymdown-extensions==10.16.1",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
[build-system]
|
|
71
|
+
requires = ["hatchling"]
|
|
72
|
+
build-backend = "hatchling.build"
|
|
73
|
+
|
|
74
|
+
[tool.hatch.build.targets.wheel]
|
|
75
|
+
packages = ["app"]
|
|
76
|
+
|
|
77
|
+
[tool.ruff]
|
|
78
|
+
line-length = 88
|
|
79
|
+
target-version = "py{{ cookiecutter.python_version.replace('.', '') }}"
|
|
80
|
+
|
|
81
|
+
[tool.ruff.lint]
|
|
82
|
+
select = ["E", "F", "I", "N", "W", "UP"] # Added UP for pyupgrade (modern Python syntax)
|
|
83
|
+
ignore = []
|
|
84
|
+
fixable = ["ALL"]
|
|
85
|
+
unfixable = []
|
|
86
|
+
|
|
87
|
+
[tool.ruff.format]
|
|
88
|
+
quote-style = "double"
|
|
89
|
+
indent-style = "space"
|
|
90
|
+
skip-magic-trailing-comma = false
|
|
91
|
+
line-ending = "auto"
|
|
92
|
+
|
|
93
|
+
[tool.ruff.lint.isort]
|
|
94
|
+
force-single-line = false
|
|
95
|
+
force-sort-within-sections = true
|
|
96
|
+
known-first-party = ["app"]
|
|
97
|
+
|
|
98
|
+
[tool.mypy]
|
|
99
|
+
python_version = "{{ cookiecutter.python_version }}"
|
|
100
|
+
strict = true
|
|
101
|
+
plugins = ["pydantic.mypy"]
|
|
102
|
+
|
|
103
|
+
[[tool.mypy.overrides]]
|
|
104
|
+
module = "flet.*"
|
|
105
|
+
ignore_missing_imports = true
|
|
106
|
+
|
|
107
|
+
{%- if cookiecutter.include_scheduler == "yes" %}
|
|
108
|
+
|
|
109
|
+
[[tool.mypy.overrides]]
|
|
110
|
+
module = "apscheduler.*"
|
|
111
|
+
ignore_missing_imports = true
|
|
112
|
+
{%- endif %}
|
|
113
|
+
|
|
114
|
+
{%- if cookiecutter.include_redis == "yes" %}
|
|
115
|
+
|
|
116
|
+
[[tool.mypy.overrides]]
|
|
117
|
+
module = "redis.*"
|
|
118
|
+
ignore_missing_imports = true
|
|
119
|
+
{%- endif %}
|
|
120
|
+
|
|
121
|
+
{%- if cookiecutter.include_worker == "yes" %}
|
|
122
|
+
|
|
123
|
+
[[tool.mypy.overrides]]
|
|
124
|
+
module = "arq.*"
|
|
125
|
+
ignore_missing_imports = true
|
|
126
|
+
{%- endif %}
|
|
127
|
+
|
|
128
|
+
{%- if cookiecutter.include_database == "yes" %}
|
|
129
|
+
|
|
130
|
+
[[tool.mypy.overrides]]
|
|
131
|
+
module = "sqlmodel.*"
|
|
132
|
+
ignore_missing_imports = true
|
|
133
|
+
{%- endif %}
|
|
134
|
+
|
|
135
|
+
# Ignore imports for future components that may not exist yet
|
|
136
|
+
[[tool.mypy.overrides]]
|
|
137
|
+
module = "app.components.database.main"
|
|
138
|
+
ignore_missing_imports = true
|
|
139
|
+
|
|
140
|
+
[[tool.mypy.overrides]]
|
|
141
|
+
module = "app.components.cache.main"
|
|
142
|
+
ignore_missing_imports = true
|
|
143
|
+
|
|
144
|
+
[[tool.mypy.overrides]]
|
|
145
|
+
module = "app.components.worker.*"
|
|
146
|
+
ignore_missing_imports = true
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
[tool.pytest.ini_options]
|
|
150
|
+
asyncio_mode = "auto"
|
|
151
|
+
testpaths = ["tests"]
|
|
152
|
+
|
|
153
|
+
[dependency-groups]
|
|
154
|
+
dev = [
|
|
155
|
+
"httpx>=0.28.1",
|
|
156
|
+
]
|
aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/entrypoint.sh
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
# More comprehensive venv cleanup to prevent Docker container conflicts
|
|
6
|
+
if [ -d ".venv" ]; then
|
|
7
|
+
echo "🧹 Found existing .venv directory, checking compatibility..."
|
|
8
|
+
|
|
9
|
+
# Check if .venv has issues (broken symlinks, wrong Python version, etc.)
|
|
10
|
+
if [ -L ".venv/bin/python3" ] && [ ! -e ".venv/bin/python3" ]; then
|
|
11
|
+
echo "🧹 Cleaning up broken venv symlinks..."
|
|
12
|
+
rm -rf .venv
|
|
13
|
+
elif [ -f ".venv/bin/python3" ]; then
|
|
14
|
+
# Check if the Python executable is compatible and accessible
|
|
15
|
+
if ! .venv/bin/python3 --version > /dev/null 2>&1; then
|
|
16
|
+
echo "🧹 Cleaning up incompatible venv..."
|
|
17
|
+
rm -rf .venv
|
|
18
|
+
fi
|
|
19
|
+
elif [ ! -w ".venv" ] || [ ! -x ".venv" ]; then
|
|
20
|
+
# Check for permission issues in Docker containers
|
|
21
|
+
echo "🧹 Cleaning up venv with permission issues..."
|
|
22
|
+
rm -rf .venv
|
|
23
|
+
else
|
|
24
|
+
# If directory exists but has no python executable, clean it up
|
|
25
|
+
if [ ! -f ".venv/bin/python3" ] && [ ! -f ".venv/bin/python" ]; then
|
|
26
|
+
echo "🧹 Cleaning up incomplete venv..."
|
|
27
|
+
rm -rf .venv
|
|
28
|
+
fi
|
|
29
|
+
fi
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# Configure UV environment based on execution context
|
|
33
|
+
if [ -n "$DOCKER_CONTAINER" ] || [ "$USER" = "root" ]; then
|
|
34
|
+
echo "🐳 Running in Docker container, configuring UV for containerized environment..."
|
|
35
|
+
|
|
36
|
+
# Set Docker-specific UV configuration
|
|
37
|
+
export UV_PROJECT_ENVIRONMENT=/code/.venv
|
|
38
|
+
export UV_LINK_MODE=copy
|
|
39
|
+
export VIRTUAL_ENV=/code/.venv
|
|
40
|
+
|
|
41
|
+
# Ensure .venv path is in PATH for CLI commands
|
|
42
|
+
export PATH="/code/.venv/bin:$PATH"
|
|
43
|
+
|
|
44
|
+
echo "✅ UV configured for Docker: UV_PROJECT_ENVIRONMENT=/code/.venv"
|
|
45
|
+
else
|
|
46
|
+
echo "🖥️ Running in local environment, UV will use project defaults"
|
|
47
|
+
|
|
48
|
+
# Ensure we don't inherit Docker environment variables
|
|
49
|
+
unset UV_PROJECT_ENVIRONMENT
|
|
50
|
+
unset UV_SYSTEM_PYTHON
|
|
51
|
+
|
|
52
|
+
# Let UV auto-detect local .venv
|
|
53
|
+
echo "✅ UV configured for local development"
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Pop run_command from arguments
|
|
57
|
+
run_command="$1"
|
|
58
|
+
shift
|
|
59
|
+
|
|
60
|
+
if [ "$run_command" = "webserver" ]; then
|
|
61
|
+
# Web server (FastAPI + Flet)
|
|
62
|
+
uv run python -m app.entrypoints.webserver
|
|
63
|
+
elif [ "$run_command" = "scheduler" ]; then
|
|
64
|
+
# Scheduler component
|
|
65
|
+
uv run python -m app.entrypoints.scheduler
|
|
66
|
+
elif [ "$run_command" = "lint" ]; then
|
|
67
|
+
uv run ruff check .
|
|
68
|
+
elif [ "$run_command" = "typecheck" ]; then
|
|
69
|
+
uv run mypy .
|
|
70
|
+
elif [ "$run_command" = "test" ]; then
|
|
71
|
+
uv run pytest "$@"
|
|
72
|
+
elif [ "$run_command" = "health" ]; then
|
|
73
|
+
uv run python -m app.cli.health check "$@"
|
|
74
|
+
elif [ "$run_command" = "help" ]; then
|
|
75
|
+
echo "Available commands:"
|
|
76
|
+
echo " webserver - Run FastAPI + Flet web server"
|
|
77
|
+
echo " scheduler - Run scheduler component"
|
|
78
|
+
echo " health - Check system health status"
|
|
79
|
+
echo " lint - Run ruff linting"
|
|
80
|
+
echo " typecheck - Run mypy type checking"
|
|
81
|
+
echo " test - Run pytest test suite"
|
|
82
|
+
echo " help - Show this help message"
|
|
83
|
+
else
|
|
84
|
+
echo "Unknown command: $run_command"
|
|
85
|
+
echo "Available commands: webserver, scheduler, health, lint, typecheck, test, help"
|
|
86
|
+
exit 1
|
|
87
|
+
fi
|