aegis-stack 0.2.0rc2__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.
- aegis/__init__.py +5 -0
- aegis/__main__.py +51 -0
- aegis/cli/__init__.py +6 -0
- aegis/cli/callbacks.py +114 -0
- aegis/cli/interactive.py +611 -0
- aegis/cli/utils.py +70 -0
- aegis/cli/validators.py +34 -0
- aegis/commands/__init__.py +6 -0
- aegis/commands/add.py +353 -0
- aegis/commands/add_service.py +332 -0
- aegis/commands/components.py +35 -0
- aegis/commands/init.py +370 -0
- aegis/commands/remove.py +227 -0
- aegis/commands/services.py +52 -0
- aegis/commands/update.py +252 -0
- aegis/commands/version.py +12 -0
- aegis/config/__init__.py +1 -0
- aegis/config/shared_files.py +136 -0
- aegis/core/CLAUDE.md +377 -0
- aegis/core/__init__.py +6 -0
- aegis/core/component_files.py +228 -0
- aegis/core/component_utils.py +220 -0
- aegis/core/components.py +127 -0
- aegis/core/copier_manager.py +315 -0
- aegis/core/copier_updater.py +475 -0
- aegis/core/dependency_resolver.py +119 -0
- aegis/core/manual_updater.py +554 -0
- aegis/core/post_gen_tasks.py +547 -0
- aegis/core/service_resolver.py +261 -0
- aegis/core/services.py +157 -0
- aegis/core/template_generator.py +266 -0
- aegis/core/version_compatibility.py +259 -0
- aegis/templates/CLAUDE.md +591 -0
- aegis/templates/cookiecutter-aegis-project/cookiecutter.json +39 -0
- aegis/templates/cookiecutter-aegis-project/hooks/post_gen_project.py +214 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.dockerignore +71 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.env.example.j2 +130 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.gitignore +131 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/Dockerfile +53 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/Makefile +236 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/README.md.j2 +196 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/alembic.ini.j2 +111 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/env.py.j2 +91 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/script.py.mako +25 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/versions/001_initial_auth.py.j2 +51 -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/ai.py.j2 +700 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/ai_rendering.py +361 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/auth.py.j2 +253 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/health.py.j2 +419 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/load_test.py.j2 +656 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/main.py.j2 +65 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/marko_terminal_renderer.py +489 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/tasks.py.j2 +328 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/{% if cookiecutter.include_scheduler == /"yes/" %}tasks.py{% endif %}" +340 -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/ai/__init__.py +8 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/ai/router.py +329 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/auth/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/auth/router.py +64 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/deps.py +58 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/health.py +163 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/models.py.j2 +280 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/routing.py.j2 +32 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/scheduler.py.j2 +121 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/worker.py.j2 +478 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/hooks.py +144 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/main.py +31 -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 +418 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/startup/database_init.py.j2 +83 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/__init__.py +5 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/controls/__init__.py +27 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/controls/table.py +78 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/controls/text.py +142 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/__init__.py.j2 +47 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/ai_card.py +287 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/auth_card.py +198 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/base_card.py +256 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/card_factory.py +227 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/card_utils.py +333 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/database_card.py +420 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/fastapi_card.py +328 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/flet_card.py +267 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/redis_card.py +322 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/scheduler_card.py +352 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/services_card.py +233 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/worker_card.py +684 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/main.py.j2 +653 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/theme.py +48 -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.j2 +156 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/CLAUDE.md.j2 +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 +97 -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 +55 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/media.py +49 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/system.py +44 -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 +120 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/load_tasks.py +507 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/simple_system_tasks.py +33 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/system_tasks.py +281 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/config.py.j2 +178 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/constants.py +58 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/db.py.j2 +176 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/log.py +92 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/security.py +62 -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 +62 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/models/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/models/user.py +44 -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/ai/__init__.py +8 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/config.py +130 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/conversation.py +213 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/health.py +96 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/models.py +229 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/providers.py +370 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/service.py +388 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/auth_service.py +41 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/health.py +164 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/user_service.py +83 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/backend/middleware_inspector.py.j2 +223 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/backend/models.py.j2 +70 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/backend/route_inspector.py.j2 +155 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/load_test.py +679 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/load_test_models.py +266 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/__init__.py.j2 +21 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/models.py.j2 +119 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/scheduled_task_manager.py.j2 +273 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/task_monitor.py.j2 +189 -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/backup.py.j2 +119 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/health.py.j2 +1333 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/models.py +243 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/ui.py +52 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/assets/aegis-manifesto-dark.png +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/assets/aegis-manifesto-square-backup.png +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/assets/aegis-manifesto.png +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/.dockerignore +71 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/.env.example.j2 +64 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/.gitignore +131 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/Dockerfile +53 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/Makefile +211 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/README.md.j2 +172 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/docker-compose.yml.j2 +78 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/mkdocs.yml.j2 +62 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/pyproject.toml.j2 +120 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/uv.lock +1673 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docker-compose.yml.j2 +200 -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 +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/components/scheduler.md.j2 +621 -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 +131 -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 +93 -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_auth_endpoints.py.j2 +307 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_health_endpoints.py.j2 +262 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_scheduler_endpoints.py.j2 +214 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_worker_endpoints.py.j2 +165 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/cli/test_ai_rendering.py +427 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/cli/test_conversation_memory.py +465 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/components/test_scheduler.py +43 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/conftest.py.j2 +195 -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/ai/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/conftest.py +78 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/test_health.py +157 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/test_models.py +164 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/test_service.py +198 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_auth_integration.py.j2 +528 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_component_integration.py.j2 +387 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_conversation_persistence.py +342 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_health_logic.py.j2 +663 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_load_test_models.py +619 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_load_test_service.py +603 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_middleware_inspector.py.j2 +248 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_scheduled_task_manager.py.j2 +292 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_system_service.py +98 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_worker_health_registration.py.j2 +257 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/test_core.py +49 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/uv.lock +1673 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/.copier-answers.yml.jinja +21 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/.dockerignore +71 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/.env.example.jinja +130 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/.gitignore +131 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/Dockerfile +53 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/Makefile.jinja +236 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/README.md.jinja +196 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/alembic.ini.jinja +111 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/env.py.jinja +91 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/script.py.mako +25 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/versions/001_initial_auth.py.jinja +51 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/__init__.py.jinja +5 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/__init__.py.jinja +6 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/ai.py.jinja +700 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/ai_rendering.py +360 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/auth.py.jinja +253 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/health.py.jinja +419 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/load_test.py.jinja +656 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/main.py.jinja +65 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/marko_terminal_renderer.py +489 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/tasks.py.jinja +328 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/__init__.py +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/__init__.py +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/ai/__init__.py +8 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/ai/router.py +329 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/auth/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/auth/router.py +64 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/deps.py +58 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/health.py.jinja +163 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/models.py.jinja +280 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/routing.py.jinja +32 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/scheduler.py.jinja +121 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/worker.py.jinja +478 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/hooks.py +144 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/main.py +31 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/middleware/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/middleware/cors.py +20 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/shutdown/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/shutdown/cleanup.py +14 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/startup/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/startup/component_health.py.jinja +418 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/startup/database_init.py.jinja +83 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/__init__.py +5 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/__init__.py +27 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/table.py +78 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/text.py +142 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/__init__.py.jinja +47 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/ai_card.py +287 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/auth_card.py +198 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/base_card.py +256 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/card_factory.py +227 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/card_utils.py +333 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/database_card.py +420 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/fastapi_card.py +328 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/flet_card.py +267 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/redis_card.py +322 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/scheduler_card.py +352 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/services_card.py +233 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/worker_card.py +684 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/main.py.jinja +653 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/theme.py +48 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/scheduler/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/scheduler/main.py.jinja +156 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/CLAUDE.md.jinja +213 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/__init__.py +6 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/constants.py.jinja +30 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/pools.py +97 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/load_test.py +55 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/media.py +49 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/system.py +44 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/registry.py +139 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/__init__.py +120 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/load_tasks.py +507 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/simple_system_tasks.py +33 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/system_tasks.py +281 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/config.py.jinja +178 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/constants.py +58 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/db.py.jinja +176 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/log.py +92 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/security.py +62 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/entrypoints/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/entrypoints/scheduler.py.jinja +21 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/entrypoints/webserver.py +39 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/integrations/__init__.py +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/integrations/main.py +61 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/models/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/models/user.py +44 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/py.typed +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/__init__.py +8 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/config.py +130 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/conversation.py +213 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/health.py +96 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/models.py +229 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/providers.py.jinja +370 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/service.py +387 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/auth_service.py +40 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/health.py +162 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/user_service.py +82 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/backend/middleware_inspector.py.jinja +223 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/backend/models.py.jinja +70 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/backend/route_inspector.py.jinja +155 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/load_test.py +678 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/load_test_models.py +265 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/__init__.py.jinja +21 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/models.py.jinja +119 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/scheduled_task_manager.py.jinja +273 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/task_monitor.py.jinja +189 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/shared/__init__.py +15 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/shared/models.py +26 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/__init__.py +52 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/alerts.py +94 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/backup.py.jinja +119 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/health.py.jinja +1333 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/models.py +243 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/ui.py +52 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57223!aegis-manifesto.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57224!aegis-manifesto-dark.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57225!aegis-manifesto-square-backup.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57533!aegis-manifesto.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57534!aegis-manifesto-dark.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57538!aegis-manifesto-square-backup.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57897!aegis-manifesto.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57898!aegis-manifesto-dark.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57904!aegis-manifesto-square-backup.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58315!aegis-manifesto.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58316!aegis-manifesto-dark.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58324!aegis-manifesto-square-backup.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58837!aegis-manifesto.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58838!aegis-manifesto-dark.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58849!aegis-manifesto-square-backup.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/aegis-manifesto-dark.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/aegis-manifesto-square-backup.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/aegis-manifesto.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/.env.example.jinja +64 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/README.md.jinja +172 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/docker-compose.yml.jinja +78 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/mkdocs.yml.jinja +62 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/pyproject.toml.jinja +120 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docker-compose.yml.jinja +200 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/api.md.jinja +191 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/components/scheduler.md +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/components/scheduler.md.jinja +621 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/development.md.jinja +215 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/health.md.jinja +240 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/javascripts/mermaid-config.js +62 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/stylesheets/mermaid.css +95 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/mkdocs.yml.jinja +62 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/pyproject.toml.jinja +131 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/scripts/entrypoint.sh +87 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/scripts/entrypoint.sh.jinja +93 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/scripts/gen_docs.py +16 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_auth_endpoints.py.jinja +307 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_health_endpoints.py.jinja +262 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_scheduler_endpoints.py.jinja +214 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_worker_endpoints.py.jinja +165 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/cli/test_ai_rendering.py +427 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/cli/test_conversation_memory.py +465 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/components/test_scheduler.py +43 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/conftest.py.jinja +195 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/conftest.py +78 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/test_health.py +157 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/test_models.py +164 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/test_service.py +198 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_auth_integration.py.jinja +528 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_component_integration.py.jinja +387 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_conversation_persistence.py +342 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_health_logic.py.jinja +663 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_load_test_models.py +619 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_load_test_service.py +603 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_middleware_inspector.py.jinja +248 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_scheduled_task_manager.py.jinja +292 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_system_service.py +98 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_worker_health_registration.py.jinja +257 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/test_core.py +49 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/uv.lock +1673 -0
- aegis_stack-0.2.0rc2.dist-info/METADATA +165 -0
- aegis_stack-0.2.0rc2.dist-info/RECORD +392 -0
- aegis_stack-0.2.0rc2.dist-info/WHEEL +4 -0
- aegis_stack-0.2.0rc2.dist-info/entry_points.txt +3 -0
- aegis_stack-0.2.0rc2.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
# Template Development Guide
|
|
2
|
+
|
|
3
|
+
This guide covers template development patterns for Aegis Stack's Cookiecutter templates.
|
|
4
|
+
|
|
5
|
+
## Template Architecture
|
|
6
|
+
|
|
7
|
+
### Template Structure
|
|
8
|
+
```
|
|
9
|
+
aegis/templates/cookiecutter-aegis-project/
|
|
10
|
+
├── cookiecutter.json # Template variables
|
|
11
|
+
├── hooks/
|
|
12
|
+
│ └── post_gen_project.py # Template processing logic
|
|
13
|
+
└── {{cookiecutter.project_slug}}/ # Generated project structure
|
|
14
|
+
├── app/
|
|
15
|
+
│ ├── components/
|
|
16
|
+
│ │ ├── backend/ # Always included
|
|
17
|
+
│ │ ├── frontend/ # Always included
|
|
18
|
+
│ │ ├── scheduler/ # Optional component
|
|
19
|
+
│ │ └── worker/ # Optional component
|
|
20
|
+
│ ├── core/ # Framework utilities
|
|
21
|
+
│ ├── entrypoints/ # Execution modes
|
|
22
|
+
│ ├── integrations/ # App composition
|
|
23
|
+
│ └── services/ # Business logic (empty)
|
|
24
|
+
├── tests/
|
|
25
|
+
├── docker-compose.yml.j2 # Conditional services
|
|
26
|
+
├── Dockerfile.j2 # Conditional entrypoints
|
|
27
|
+
├── pyproject.toml.j2 # Dependencies and configuration
|
|
28
|
+
└── scripts/entrypoint.sh.j2 # Runtime dispatch
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Template Processing Flow
|
|
32
|
+
1. **Cookiecutter generates** base project structure using `cookiecutter.json`
|
|
33
|
+
2. **Post-generation hook** (`hooks/post_gen_project.py`) processes `.j2` files with Jinja2
|
|
34
|
+
3. **Component selection** includes/excludes files based on user choices
|
|
35
|
+
4. **Auto-formatting** runs `make fix` on generated project
|
|
36
|
+
5. **Cleanup** removes unused template files and `.j2` originals
|
|
37
|
+
|
|
38
|
+
## Cookiecutter Variables
|
|
39
|
+
|
|
40
|
+
### Core Variables (cookiecutter.json)
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"project_name": "My Aegis Project",
|
|
44
|
+
"project_slug": "{{ cookiecutter.project_name|lower|replace(' ', '-')|replace('_', '-') }}",
|
|
45
|
+
"project_description": "A production-ready Python application",
|
|
46
|
+
"author_name": "Your Name",
|
|
47
|
+
"author_email": "your.email@example.com",
|
|
48
|
+
"version": "0.1.0",
|
|
49
|
+
"python_version": "3.11",
|
|
50
|
+
"include_scheduler": "no",
|
|
51
|
+
"include_worker": "no",
|
|
52
|
+
"include_database": "no"
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Variable Usage in Templates
|
|
57
|
+
```jinja2
|
|
58
|
+
# In any .j2 file
|
|
59
|
+
{{ cookiecutter.project_name }} # "My Aegis Project"
|
|
60
|
+
{{ cookiecutter.project_slug }} # "my-aegis-project"
|
|
61
|
+
{{ cookiecutter.project_description }} # Description text
|
|
62
|
+
{{ cookiecutter.author_name }} # Author info
|
|
63
|
+
{{ cookiecutter.include_scheduler }} # "yes" or "no"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Jinja2 Template Patterns
|
|
67
|
+
|
|
68
|
+
### Conditional Content
|
|
69
|
+
```jinja2
|
|
70
|
+
{% if cookiecutter.include_scheduler == "yes" %}
|
|
71
|
+
# Scheduler-specific content
|
|
72
|
+
{% endif %}
|
|
73
|
+
|
|
74
|
+
{% if cookiecutter.include_worker == "yes" %}
|
|
75
|
+
# Worker-specific content
|
|
76
|
+
{% endif %}
|
|
77
|
+
|
|
78
|
+
{% if cookiecutter.include_database == "yes" %}
|
|
79
|
+
# Database-specific content
|
|
80
|
+
{% endif %}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Conditional Files
|
|
84
|
+
File names can be conditional:
|
|
85
|
+
```
|
|
86
|
+
{% if cookiecutter.include_scheduler == "yes" %}scheduler.py{% endif %}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Variable Substitution in Code
|
|
90
|
+
```python
|
|
91
|
+
# In .j2 files
|
|
92
|
+
CLI_NAME = "{{ cookiecutter.project_slug }}"
|
|
93
|
+
PROJECT_NAME = "{{ cookiecutter.project_name }}"
|
|
94
|
+
VERSION = "{{ cookiecutter.version }}"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Dependencies Based on Components
|
|
98
|
+
```toml
|
|
99
|
+
# pyproject.toml.j2
|
|
100
|
+
dependencies = [
|
|
101
|
+
"fastapi>=0.116.1",
|
|
102
|
+
"flet>=0.28.3",
|
|
103
|
+
{% if cookiecutter.include_scheduler == "yes" %}
|
|
104
|
+
"apscheduler>=3.10.0",
|
|
105
|
+
{% endif %}
|
|
106
|
+
{% if cookiecutter.include_worker == "yes" %}
|
|
107
|
+
"arq>=0.26.1",
|
|
108
|
+
"redis>=5.2.1",
|
|
109
|
+
{% endif %}
|
|
110
|
+
{% if cookiecutter.include_database == "yes" %}
|
|
111
|
+
"sqlmodel>=0.0.14",
|
|
112
|
+
"sqlalchemy>=2.0.0",
|
|
113
|
+
"aiosqlite>=0.19.0",
|
|
114
|
+
{% endif %}
|
|
115
|
+
]
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Post-Generation Hook Patterns
|
|
119
|
+
|
|
120
|
+
### Hook Responsibilities
|
|
121
|
+
The `hooks/post_gen_project.py` script:
|
|
122
|
+
1. **Processes .j2 files** - Renders Jinja2 templates with cookiecutter context
|
|
123
|
+
2. **Removes unused files** - Deletes component files when components not selected
|
|
124
|
+
3. **Cleans up directories** - Removes empty directories after file cleanup
|
|
125
|
+
4. **Auto-formats code** - Runs `make fix` to ensure generated code is clean
|
|
126
|
+
|
|
127
|
+
### Adding New Component Logic
|
|
128
|
+
```python
|
|
129
|
+
# In hooks/post_gen_project.py
|
|
130
|
+
if "{{ cookiecutter.include_new_component }}" != "yes":
|
|
131
|
+
# Remove component-specific files
|
|
132
|
+
remove_dir("app/components/new_component")
|
|
133
|
+
remove_file("app/entrypoints/new_component.py")
|
|
134
|
+
remove_file("tests/components/test_new_component.py")
|
|
135
|
+
|
|
136
|
+
# Database component logic
|
|
137
|
+
if "{{ cookiecutter.include_database }}" != "yes":
|
|
138
|
+
remove_file("app/core/db.py")
|
|
139
|
+
remove_sections_from_conftest("tests/conftest.py", ["database"])
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### File Removal Patterns
|
|
143
|
+
```python
|
|
144
|
+
# Remove individual files
|
|
145
|
+
remove_file("app/components/scheduler.py")
|
|
146
|
+
remove_file("tests/components/test_scheduler.py")
|
|
147
|
+
|
|
148
|
+
# Remove entire directories
|
|
149
|
+
remove_dir("app/components/worker")
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Template Development Workflow
|
|
153
|
+
|
|
154
|
+
### CRITICAL: Never Edit Generated Projects
|
|
155
|
+
**Always follow this pattern:**
|
|
156
|
+
|
|
157
|
+
1. **Edit template files** in `aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/`
|
|
158
|
+
2. **Test template changes**: `make test-template`
|
|
159
|
+
3. **If tests fail**: Fix the **template files** (step 1), never the generated projects
|
|
160
|
+
4. **Repeat** until tests pass
|
|
161
|
+
5. **Clean up**: `make clean-test-projects`
|
|
162
|
+
|
|
163
|
+
### Adding New Template Files
|
|
164
|
+
```bash
|
|
165
|
+
# 1. Create template file
|
|
166
|
+
vim aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/new_component.py
|
|
167
|
+
|
|
168
|
+
# 2. If using variables, make it a .j2 file
|
|
169
|
+
mv app/components/new_component.py app/components/new_component.py.j2
|
|
170
|
+
|
|
171
|
+
# 3. Add conditional logic to hook if needed
|
|
172
|
+
vim hooks/post_gen_project.py
|
|
173
|
+
|
|
174
|
+
# 4. Test the changes
|
|
175
|
+
make test-template
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Modifying Existing Templates
|
|
179
|
+
```bash
|
|
180
|
+
# 1. Find the template file
|
|
181
|
+
find aegis/templates/ -name "*.py" -o -name "*.j2" | grep component_name
|
|
182
|
+
|
|
183
|
+
# 2. Edit the template
|
|
184
|
+
vim aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/path/to/file.j2
|
|
185
|
+
|
|
186
|
+
# 3. Test immediately
|
|
187
|
+
make test-template-quick
|
|
188
|
+
|
|
189
|
+
# 4. Full validation
|
|
190
|
+
make test-template
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Template Testing Integration
|
|
194
|
+
|
|
195
|
+
### Template Validation Process
|
|
196
|
+
When you run `make test-template`:
|
|
197
|
+
1. **Generates fresh project** using current templates
|
|
198
|
+
2. **Processes .j2 files** through post-generation hook
|
|
199
|
+
3. **Installs dependencies** in generated project
|
|
200
|
+
4. **Runs quality checks** (lint, typecheck, tests)
|
|
201
|
+
5. **Tests CLI installation** and functionality
|
|
202
|
+
|
|
203
|
+
### Template-Specific Test Commands
|
|
204
|
+
```bash
|
|
205
|
+
make test-template # Test basic project generation
|
|
206
|
+
make test-template-with-components # Test with scheduler component
|
|
207
|
+
make test-template-worker # Test worker component
|
|
208
|
+
make test-template-full # Test all components
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Auto-Fixing in Templates
|
|
212
|
+
The template system automatically:
|
|
213
|
+
- **Fixes linting issues** in generated code
|
|
214
|
+
- **Formats code** with ruff
|
|
215
|
+
- **Ensures proper imports** and structure
|
|
216
|
+
- **Validates type annotations**
|
|
217
|
+
|
|
218
|
+
## Common Template Patterns
|
|
219
|
+
|
|
220
|
+
### Configuration Management
|
|
221
|
+
```python
|
|
222
|
+
# Use in templates for environment-dependent values
|
|
223
|
+
from app.core.config import settings
|
|
224
|
+
|
|
225
|
+
# Template generates proper imports
|
|
226
|
+
DATABASE_URL = settings.DATABASE_URL
|
|
227
|
+
REDIS_URL = settings.REDIS_URL
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Component Registration
|
|
231
|
+
```python
|
|
232
|
+
# Backend component registration
|
|
233
|
+
# In app/components/backend/startup/component_health.py.j2
|
|
234
|
+
{% if cookiecutter.include_worker == "yes" %}
|
|
235
|
+
from app.components.worker.health import register_worker_health_checks
|
|
236
|
+
{% endif %}
|
|
237
|
+
|
|
238
|
+
async def register_component_health_checks() -> None:
|
|
239
|
+
"""Register health checks for all enabled components."""
|
|
240
|
+
{% if cookiecutter.include_worker == "yes" %}
|
|
241
|
+
register_worker_health_checks()
|
|
242
|
+
{% endif %}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Docker Service Configuration
|
|
246
|
+
```yaml
|
|
247
|
+
# docker-compose.yml.j2
|
|
248
|
+
services:
|
|
249
|
+
webserver:
|
|
250
|
+
# Always included
|
|
251
|
+
|
|
252
|
+
{% if cookiecutter.include_worker == "yes" %}
|
|
253
|
+
worker-system:
|
|
254
|
+
build: .
|
|
255
|
+
command: ["worker-system"]
|
|
256
|
+
depends_on:
|
|
257
|
+
- redis
|
|
258
|
+
{% endif %}
|
|
259
|
+
|
|
260
|
+
{% if cookiecutter.include_scheduler == "yes" %}
|
|
261
|
+
scheduler:
|
|
262
|
+
build: .
|
|
263
|
+
command: ["scheduler"]
|
|
264
|
+
{% endif %}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Template Debugging
|
|
268
|
+
|
|
269
|
+
### Common Template Issues
|
|
270
|
+
- **Jinja2 syntax errors** - Check bracket matching, endif statements
|
|
271
|
+
- **Missing cookiecutter variables** - Verify variable names in cookiecutter.json
|
|
272
|
+
- **Conditional logic errors** - Test with different component combinations
|
|
273
|
+
- **File path issues** - Ensure proper directory structure
|
|
274
|
+
|
|
275
|
+
### Debugging Template Generation
|
|
276
|
+
```bash
|
|
277
|
+
# Generate project manually for debugging
|
|
278
|
+
uv run aegis init debug-project --output-dir ../debug --force --yes
|
|
279
|
+
|
|
280
|
+
# Check generated files
|
|
281
|
+
ls -la ../debug-project/
|
|
282
|
+
|
|
283
|
+
# Look for remaining .j2 files (should be none)
|
|
284
|
+
find ../debug-project/ -name "*.j2"
|
|
285
|
+
|
|
286
|
+
# Check variable substitution
|
|
287
|
+
grep -r "cookiecutter\." ../debug-project/ || echo "No unreplaced variables"
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Testing Individual Components
|
|
291
|
+
```bash
|
|
292
|
+
# Test specific component combinations
|
|
293
|
+
make test-template-worker # Just worker component
|
|
294
|
+
make test-template-with-components # Just scheduler component
|
|
295
|
+
make test-template-full # All components
|
|
296
|
+
|
|
297
|
+
# Clean up between tests
|
|
298
|
+
make clean-test-projects
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Template Quality Standards
|
|
302
|
+
|
|
303
|
+
### Code Generation Requirements
|
|
304
|
+
- **No .j2 files** remain in generated projects
|
|
305
|
+
- **All variables replaced** - no `{{ cookiecutter.* }}` in final code
|
|
306
|
+
- **Proper imports** - only import what's needed based on components
|
|
307
|
+
- **Type annotations** - all generated code must be properly typed
|
|
308
|
+
- **Linting passes** - generated code passes ruff checks
|
|
309
|
+
- **Tests included** - component tests generated with components
|
|
310
|
+
|
|
311
|
+
### Component Isolation
|
|
312
|
+
- **Independent components** - each component can be enabled/disabled
|
|
313
|
+
- **Clean dependencies** - components only depend on what they need
|
|
314
|
+
- **Proper cleanup** - unused files removed when components disabled
|
|
315
|
+
- **No broken imports** - imports only exist when dependencies available
|
|
316
|
+
|
|
317
|
+
### File Organization
|
|
318
|
+
- **Consistent structure** - follow established patterns
|
|
319
|
+
- **Logical grouping** - related files in same directories
|
|
320
|
+
- **Clear naming** - descriptive file and directory names
|
|
321
|
+
- **Proper permissions** - executable files marked as executable
|
|
322
|
+
|
|
323
|
+
## Template Parity Patterns (Cookiecutter ↔ Copier Migration)
|
|
324
|
+
|
|
325
|
+
### Overview
|
|
326
|
+
Aegis Stack maintains two parallel template engines during migration:
|
|
327
|
+
- **Cookiecutter** (legacy) - Uses `cookiecutter.json` + `.j2` files + post-generation hooks
|
|
328
|
+
- **Copier** (modern) - Uses `copier.yml` + `.jinja` files + built-in tasks
|
|
329
|
+
|
|
330
|
+
Both engines MUST generate byte-for-byte identical projects. The `tests/test_template_parity.py` suite verifies this across all component/service combinations.
|
|
331
|
+
|
|
332
|
+
### Critical Pattern #1: Whitespace Control
|
|
333
|
+
|
|
334
|
+
**Problem**: Jinja2's `{%-` strips ALL preceding whitespace, including intentional blank lines.
|
|
335
|
+
|
|
336
|
+
**Rule**: Copier templates must match Cookiecutter's whitespace preservation.
|
|
337
|
+
|
|
338
|
+
```jinja2
|
|
339
|
+
# ❌ WRONG - Copier template (strips blank lines)
|
|
340
|
+
from app.core.log import logger
|
|
341
|
+
|
|
342
|
+
{%- if include_auth %}
|
|
343
|
+
from app.models.user import User
|
|
344
|
+
{% endif %}
|
|
345
|
+
|
|
346
|
+
# ✅ CORRECT - Matches Cookiecutter
|
|
347
|
+
from app.core.log import logger
|
|
348
|
+
|
|
349
|
+
{% if include_auth %}
|
|
350
|
+
from app.models.user import User
|
|
351
|
+
{% endif %}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**When This Matters**: When conditional blocks are skipped (e.g., `include_auth = false`), the `{%-` strips the blank line, creating a mismatch.
|
|
355
|
+
|
|
356
|
+
**Detection**: If parity tests show line number differences or unexpected blank lines, search for `{%-` in Copier templates.
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
# Find all whitespace control usage
|
|
360
|
+
grep -n '{%-' aegis/templates/copier-aegis-project/**/*.jinja
|
|
361
|
+
|
|
362
|
+
# Compare with Cookiecutter equivalent
|
|
363
|
+
grep -n '{%' aegis/templates/cookiecutter-aegis-project/**/*.j2
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Critical Pattern #2: Type Mismatches (Boolean vs String)
|
|
367
|
+
|
|
368
|
+
**Problem**: Cookiecutter uses strings (`"yes"/"no"`), Copier uses native booleans (`true/false`).
|
|
369
|
+
|
|
370
|
+
**Rule**: Copier templates must use boolean logic, not string comparisons.
|
|
371
|
+
|
|
372
|
+
```jinja2
|
|
373
|
+
# ❌ WRONG - Copier template comparing boolean to string
|
|
374
|
+
{% if include_worker == "yes" %}
|
|
375
|
+
from app.components.worker import WorkerConfig
|
|
376
|
+
{% endif %}
|
|
377
|
+
|
|
378
|
+
# ✅ CORRECT - Boolean comparison
|
|
379
|
+
{% if include_worker %}
|
|
380
|
+
from app.components.worker import WorkerConfig
|
|
381
|
+
{% endif %}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**Common Mistakes**:
|
|
385
|
+
```jinja2
|
|
386
|
+
# Cookiecutter (strings)
|
|
387
|
+
{% if cookiecutter.include_auth == "yes" %}
|
|
388
|
+
{% if cookiecutter.include_scheduler == "yes" and cookiecutter.include_database == "yes" %}
|
|
389
|
+
|
|
390
|
+
# Copier (booleans)
|
|
391
|
+
{% if include_auth %}
|
|
392
|
+
{% if include_scheduler and include_database %}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**Detection**: If conditional content is missing from Copier output, check for string comparisons against boolean variables.
|
|
396
|
+
|
|
397
|
+
### Critical Pattern #3: Service Dependency Auto-Resolution
|
|
398
|
+
|
|
399
|
+
**Problem**: Services declare `required_components` but templates must honor these dependencies.
|
|
400
|
+
|
|
401
|
+
**Architecture**:
|
|
402
|
+
```python
|
|
403
|
+
# aegis/core/services.py
|
|
404
|
+
SERVICES = {
|
|
405
|
+
"auth": ServiceSpec(
|
|
406
|
+
name="auth",
|
|
407
|
+
required_components=["backend", "database"], # Auth needs database!
|
|
408
|
+
),
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
# aegis/core/template_generator.py
|
|
412
|
+
# ✅ CORRECT - Auto-add service dependencies
|
|
413
|
+
for service_name in self.selected_services:
|
|
414
|
+
if service_name in SERVICES:
|
|
415
|
+
service_spec = SERVICES[service_name]
|
|
416
|
+
all_components.extend(service_spec.required_components)
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**Impact**: When `--services auth` is used, database component must be automatically enabled. Without this, alembic migrations fail with `ModuleNotFoundError: No module named 'sqlmodel'`.
|
|
420
|
+
|
|
421
|
+
**Testing**:
|
|
422
|
+
```bash
|
|
423
|
+
# Auth service should auto-enable database
|
|
424
|
+
make test-parity # Includes test_parity_with_auth_service
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Critical Pattern #4: File Exclusion Consistency
|
|
428
|
+
|
|
429
|
+
**Problem**: Both templates must exclude the same files based on component selection.
|
|
430
|
+
|
|
431
|
+
**Rule**: Exclusions must match in both `copier.yml` and `hooks/post_gen_project.py`.
|
|
432
|
+
|
|
433
|
+
```yaml
|
|
434
|
+
# copier.yml exclusions
|
|
435
|
+
_exclude:
|
|
436
|
+
# Scheduler memory backend exclusions
|
|
437
|
+
- "{% if scheduler_backend == 'memory' -%}{{ project_slug }}/app/services/scheduler{% endif %}"
|
|
438
|
+
- "{% if scheduler_backend == 'memory' -%}{{ project_slug }}/tests/services/test_scheduled_task_manager.py{% endif %}"
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
```python
|
|
442
|
+
# hooks/post_gen_project.py
|
|
443
|
+
if "{{ cookiecutter.scheduler_backend }}" == "memory":
|
|
444
|
+
remove_dir("app/services/scheduler")
|
|
445
|
+
remove_file("tests/services/test_scheduled_task_manager.py")
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**Detection**: If parity tests show file existence differences, check exclusion rules in both templates.
|
|
449
|
+
|
|
450
|
+
### Parity Testing Workflow
|
|
451
|
+
|
|
452
|
+
**Running Parity Tests**:
|
|
453
|
+
```bash
|
|
454
|
+
make test-parity # All 9 parity tests
|
|
455
|
+
make test-parity-quick # Base project only
|
|
456
|
+
make test-parity-components # All component combinations
|
|
457
|
+
make test-parity-services # All service combinations
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
**Test Matrix** (9 comprehensive tests):
|
|
461
|
+
1. `test_parity_base_project` - Backend + frontend only
|
|
462
|
+
2. `test_parity_with_scheduler_memory` - Scheduler (memory backend)
|
|
463
|
+
3. `test_parity_with_scheduler_sqlite` - Scheduler (sqlite backend)
|
|
464
|
+
4. `test_parity_with_worker` - Worker component
|
|
465
|
+
5. `test_parity_with_database` - Database component
|
|
466
|
+
6. `test_parity_with_all_components` - Worker + scheduler + database
|
|
467
|
+
7. `test_parity_with_auth_service` - Auth service (auto-enables database)
|
|
468
|
+
8. `test_parity_with_ai_service` - AI service
|
|
469
|
+
9. `test_parity_kitchen_sink` - Everything enabled
|
|
470
|
+
|
|
471
|
+
**What Parity Tests Verify**:
|
|
472
|
+
- File structure (same files exist in both outputs)
|
|
473
|
+
- File contents (byte-for-byte identical after normalization)
|
|
474
|
+
- File permissions (executables marked correctly)
|
|
475
|
+
- Template variable substitution (no unreplaced `{{ ... }}`)
|
|
476
|
+
|
|
477
|
+
**Normalization Process**:
|
|
478
|
+
Both outputs are auto-formatted with `ruff` before comparison to eliminate cosmetic differences like import ordering.
|
|
479
|
+
|
|
480
|
+
### Debugging Parity Failures
|
|
481
|
+
|
|
482
|
+
**Step 1: Identify the failure**
|
|
483
|
+
```bash
|
|
484
|
+
make test-parity 2>&1 | grep "FAILED"
|
|
485
|
+
# Example: test_parity_with_auth_service FAILED
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
**Step 2: Focus on ONE mismatch**
|
|
489
|
+
Parity test output shows specific differences:
|
|
490
|
+
```
|
|
491
|
+
📝 Content mismatches:
|
|
492
|
+
alembic/env.py:
|
|
493
|
+
Cookiecutter: line 24: ...
|
|
494
|
+
Copier: line 24: from app.models.user import User # noqa: E402,F401...
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
**Step 3: Generate both projects manually**
|
|
498
|
+
```bash
|
|
499
|
+
# Cookiecutter
|
|
500
|
+
cd /tmp
|
|
501
|
+
aegis init ck-test --services auth --no-interactive --yes --force
|
|
502
|
+
|
|
503
|
+
# Copier
|
|
504
|
+
copier copy --trust --defaults \
|
|
505
|
+
--data project_slug="cp-test" \
|
|
506
|
+
--data include_auth=true \
|
|
507
|
+
aegis/templates/copier-aegis-project /tmp/cp-test
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
**Step 4: Compare specific files**
|
|
511
|
+
```bash
|
|
512
|
+
diff -u /tmp/ck-test/alembic/env.py /tmp/cp-test/cp-test/alembic/env.py
|
|
513
|
+
|
|
514
|
+
# Check line numbers
|
|
515
|
+
sed -n '20,30p' /tmp/ck-test/alembic/env.py
|
|
516
|
+
sed -n '20,30p' /tmp/cp-test/cp-test/alembic/env.py
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
**Step 5: Identify the pattern**
|
|
520
|
+
- Blank line difference? → Check for `{%-` in Copier template
|
|
521
|
+
- Missing content? → Check for boolean vs string comparison
|
|
522
|
+
- Wrong imports? → Check service dependency resolution
|
|
523
|
+
- Missing file? → Check exclusion rules
|
|
524
|
+
|
|
525
|
+
**Step 6: Fix the template**
|
|
526
|
+
Always fix the **template files**, never the generated projects:
|
|
527
|
+
```bash
|
|
528
|
+
vim aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/env.py.jinja
|
|
529
|
+
# Change {%- if to {% if
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
**Step 7: Re-test**
|
|
533
|
+
```bash
|
|
534
|
+
make test-parity
|
|
535
|
+
# Should show one more test passing
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### Common Parity Issues
|
|
539
|
+
|
|
540
|
+
**Issue**: 56 import ordering differences
|
|
541
|
+
**Cause**: Different ruff versions or incomplete normalization
|
|
542
|
+
**Fix**: Ensure `uv sync --all-extras` runs before `make fix` in Copier tasks
|
|
543
|
+
|
|
544
|
+
**Issue**: Alembic migration fails with "No module named 'sqlmodel'"
|
|
545
|
+
**Cause**: Auth service enabled without database component
|
|
546
|
+
**Fix**: TemplateGenerator must auto-add service dependencies
|
|
547
|
+
|
|
548
|
+
**Issue**: File has 6 lines in Copier, 113 lines in Cookiecutter
|
|
549
|
+
**Cause**: Boolean comparison bug (e.g., `include_scheduler == "yes"` when it's `true`)
|
|
550
|
+
**Fix**: Change to `include_scheduler` (boolean logic)
|
|
551
|
+
|
|
552
|
+
**Issue**: Blank line mismatch at line N
|
|
553
|
+
**Cause**: Copier uses `{%-` where Cookiecutter uses `{%`
|
|
554
|
+
**Fix**: Remove `-` to preserve whitespace
|
|
555
|
+
|
|
556
|
+
### Best Practices
|
|
557
|
+
|
|
558
|
+
**When Adding New Templates**:
|
|
559
|
+
1. Create in Cookiecutter first (`.j2` files)
|
|
560
|
+
2. Copy to Copier and convert (`.jinja` files)
|
|
561
|
+
3. Update variables: `cookiecutter.var` → `var`
|
|
562
|
+
4. Update conditionals: `== "yes"` → boolean logic
|
|
563
|
+
5. Check whitespace: `{%-` → `{%` (usually)
|
|
564
|
+
6. Run `make test-parity` to verify
|
|
565
|
+
|
|
566
|
+
**When Modifying Existing Templates**:
|
|
567
|
+
1. Edit **BOTH** Cookiecutter and Copier templates
|
|
568
|
+
2. Keep the same logic, just adapt syntax
|
|
569
|
+
3. Run `make test-parity` to catch drift
|
|
570
|
+
4. Never assume templates are in sync
|
|
571
|
+
|
|
572
|
+
**When Services Change**:
|
|
573
|
+
1. Update `aegis/core/services.py` with new dependencies
|
|
574
|
+
2. Verify TemplateGenerator respects them
|
|
575
|
+
3. Add parity test case if needed
|
|
576
|
+
4. Document new service dependencies
|
|
577
|
+
|
|
578
|
+
### Success Criteria
|
|
579
|
+
|
|
580
|
+
Parity is achieved when:
|
|
581
|
+
```bash
|
|
582
|
+
make test-parity
|
|
583
|
+
# 9 passed in ~70 seconds
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
All tests MUST pass before:
|
|
587
|
+
- Merging template changes
|
|
588
|
+
- Releasing new Aegis Stack versions
|
|
589
|
+
- Switching from Cookiecutter to Copier as primary engine
|
|
590
|
+
|
|
591
|
+
**Zero tolerance for drift** - Any parity failure indicates a real problem that will affect users.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"project_name": "My Aegis Stack Project",
|
|
3
|
+
"project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '-').replace('_', '-') }}",
|
|
4
|
+
"project_description": "A production-ready async Python application built with Aegis Stack",
|
|
5
|
+
"author_name": "Your Name",
|
|
6
|
+
"author_email": "your.email@example.com",
|
|
7
|
+
"github_username": "your-username",
|
|
8
|
+
"version": "0.1.0",
|
|
9
|
+
"python_version": "3.11",
|
|
10
|
+
|
|
11
|
+
"_comment_components": "Component selection - these will be set by our CLI",
|
|
12
|
+
"include_scheduler": "no",
|
|
13
|
+
"include_redis": "no",
|
|
14
|
+
"include_worker": "no",
|
|
15
|
+
"include_database": "no",
|
|
16
|
+
"include_cache": "no",
|
|
17
|
+
"scheduler_backend": "memory",
|
|
18
|
+
"scheduler_with_persistence": "no",
|
|
19
|
+
|
|
20
|
+
"_comment_services": "Service selection - these will be set by our CLI",
|
|
21
|
+
"include_auth": "no",
|
|
22
|
+
"include_ai": "no",
|
|
23
|
+
"ai_providers": "openai",
|
|
24
|
+
|
|
25
|
+
"_comment_internal": "Internal variables for template logic",
|
|
26
|
+
"_has_additional_components": "{% if cookiecutter.include_scheduler == 'yes' or cookiecutter.include_redis == 'yes' or cookiecutter.include_worker == 'yes' or cookiecutter.include_database == 'yes' or cookiecutter.include_cache == 'yes' %}yes{% else %}no{% endif %}",
|
|
27
|
+
"_include_migrations": "{% if cookiecutter.include_auth == 'yes' %}yes{% else %}no{% endif %}",
|
|
28
|
+
|
|
29
|
+
"_comment_dependencies": "Component-specific dependencies",
|
|
30
|
+
"_scheduler_deps": "{% if cookiecutter.include_scheduler == 'yes' %}apscheduler>=3.10.0{% endif %}",
|
|
31
|
+
"_redis_deps": "{% if cookiecutter.include_redis == 'yes' %}redis>=5.0.0{% endif %}",
|
|
32
|
+
"_worker_deps": "{% if cookiecutter.include_worker == 'yes' %}arq>=0.25.0{% endif %}",
|
|
33
|
+
"_database_deps": "{% if cookiecutter.include_database == 'yes' %}sqlmodel>=0.0.14,sqlalchemy>=2.0.0,aiosqlite>=0.19.0{% endif %}",
|
|
34
|
+
"_cache_deps": "{% if cookiecutter.include_cache == 'yes' %}redis[hiredis]>=5.0.0{% endif %}",
|
|
35
|
+
|
|
36
|
+
"_comment_service_dependencies": "Service-specific dependencies",
|
|
37
|
+
"_auth_deps": "{% if cookiecutter.include_auth == 'yes' %}python-jose[cryptography]==3.3.0,passlib[bcrypt]==1.7.4,python-multipart==0.0.9{% endif %}",
|
|
38
|
+
"_ai_deps": "{% if cookiecutter.include_ai == 'yes' %}pydantic-ai-slim[{{ cookiecutter.ai_providers }}]==1.0.10,httpx>=0.27.0{% endif %}"
|
|
39
|
+
}
|