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
aegis/cli/interactive.py
ADDED
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Interactive CLI components.
|
|
3
|
+
|
|
4
|
+
This module contains interactive selection and prompting functions
|
|
5
|
+
used by CLI commands.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import typer
|
|
11
|
+
|
|
12
|
+
from ..core.components import COMPONENTS, CORE_COMPONENTS, ComponentSpec, ComponentType
|
|
13
|
+
from ..core.services import SERVICES, ServiceType, get_services_by_type
|
|
14
|
+
|
|
15
|
+
# Global variable to store AI provider selections for template generation
|
|
16
|
+
_ai_provider_selection: dict[str, list[str]] = {}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_interactive_infrastructure_components() -> list[ComponentSpec]:
|
|
20
|
+
"""Get infrastructure components available for interactive selection."""
|
|
21
|
+
# Get all infrastructure components
|
|
22
|
+
infra_components = []
|
|
23
|
+
for component_spec in COMPONENTS.values():
|
|
24
|
+
if component_spec.type == ComponentType.INFRASTRUCTURE:
|
|
25
|
+
infra_components.append(component_spec)
|
|
26
|
+
|
|
27
|
+
# Sort by name for consistent ordering
|
|
28
|
+
return sorted(infra_components, key=lambda x: x.name)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def interactive_project_selection() -> tuple[list[str], str, list[str]]:
|
|
32
|
+
"""
|
|
33
|
+
Interactive project selection with component and service options.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Tuple of (selected_components, scheduler_backend, selected_services)
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
typer.echo("šÆ Component Selection")
|
|
40
|
+
typer.echo("=" * 40)
|
|
41
|
+
typer.echo(
|
|
42
|
+
f"ā
Core components ({' + '.join(CORE_COMPONENTS)}) included automatically\n"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
selected = []
|
|
46
|
+
database_engine = None # Track database engine selection
|
|
47
|
+
database_added_by_scheduler = False # Track if database was added by scheduler
|
|
48
|
+
scheduler_backend = "memory" # Track scheduler backend: memory, sqlite, postgres
|
|
49
|
+
|
|
50
|
+
# Get all infrastructure components from registry
|
|
51
|
+
infra_components = get_interactive_infrastructure_components()
|
|
52
|
+
|
|
53
|
+
typer.echo("šļø Infrastructure Components:")
|
|
54
|
+
|
|
55
|
+
# Process components in a specific order to handle dependencies
|
|
56
|
+
component_order = ["redis", "worker", "scheduler", "database"]
|
|
57
|
+
|
|
58
|
+
for component_name in component_order:
|
|
59
|
+
# Find the component spec
|
|
60
|
+
component_spec = next(
|
|
61
|
+
(c for c in infra_components if c.name == component_name), None
|
|
62
|
+
)
|
|
63
|
+
if not component_spec:
|
|
64
|
+
continue # Skip if component doesn't exist in registry
|
|
65
|
+
|
|
66
|
+
# Handle special worker dependency logic
|
|
67
|
+
if component_name == "worker":
|
|
68
|
+
if "redis" in selected:
|
|
69
|
+
# Redis already selected, simple worker prompt
|
|
70
|
+
prompt = f" Add {component_spec.description.lower()}?"
|
|
71
|
+
if typer.confirm(prompt):
|
|
72
|
+
selected.append("worker")
|
|
73
|
+
else:
|
|
74
|
+
# Redis not selected, offer to add both
|
|
75
|
+
prompt = (
|
|
76
|
+
f" Add {component_spec.description.lower()}? (will auto-add Redis)"
|
|
77
|
+
)
|
|
78
|
+
if typer.confirm(prompt):
|
|
79
|
+
selected.extend(["redis", "worker"])
|
|
80
|
+
elif component_name == "scheduler":
|
|
81
|
+
# Enhanced scheduler selection with persistence and database options
|
|
82
|
+
prompt = f" Add {component_spec.description}?"
|
|
83
|
+
if typer.confirm(prompt):
|
|
84
|
+
selected.append("scheduler")
|
|
85
|
+
|
|
86
|
+
# Follow-up: persistence question
|
|
87
|
+
typer.echo("\nš¾ Scheduler Persistence:")
|
|
88
|
+
persistence_prompt = (
|
|
89
|
+
" Do you want to persist scheduled jobs? "
|
|
90
|
+
"(Enables job history, recovery after restarts)"
|
|
91
|
+
)
|
|
92
|
+
if typer.confirm(persistence_prompt):
|
|
93
|
+
# Database engine selection (SQLite only for now)
|
|
94
|
+
typer.echo("\nšļø Database Engine:")
|
|
95
|
+
typer.echo(" SQLite will be configured for job persistence")
|
|
96
|
+
typer.echo(" (PostgreSQL support coming in future releases)")
|
|
97
|
+
|
|
98
|
+
# Show SQLite limitations
|
|
99
|
+
typer.echo("\nā ļø SQLite Limitations:")
|
|
100
|
+
typer.echo(
|
|
101
|
+
" ⢠Multi-container API access works in development only "
|
|
102
|
+
"(shared volumes)"
|
|
103
|
+
)
|
|
104
|
+
typer.echo(" ⢠Production deployment will be single-container")
|
|
105
|
+
typer.echo(
|
|
106
|
+
" ⢠Use PostgreSQL for full production multi-container support"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
if typer.confirm(" Continue with SQLite?", default=True):
|
|
110
|
+
database_engine = "sqlite"
|
|
111
|
+
selected.append("database")
|
|
112
|
+
database_added_by_scheduler = True
|
|
113
|
+
# Mark scheduler backend as sqlite
|
|
114
|
+
scheduler_backend = "sqlite"
|
|
115
|
+
typer.echo("ā
Scheduler + SQLite database configured")
|
|
116
|
+
|
|
117
|
+
# Show bonus backup job message only when database is added
|
|
118
|
+
typer.echo("\nšÆ Bonus: Adding database backup job")
|
|
119
|
+
typer.echo(
|
|
120
|
+
"ā
Scheduled daily database backup job included "
|
|
121
|
+
"(runs at 2 AM)"
|
|
122
|
+
)
|
|
123
|
+
else:
|
|
124
|
+
typer.echo("ā¹ļø Scheduler persistence cancelled")
|
|
125
|
+
# Don't add database if user declines SQLite
|
|
126
|
+
|
|
127
|
+
typer.echo() # Extra spacing after scheduler section
|
|
128
|
+
elif component_name == "database":
|
|
129
|
+
# Skip generic database prompt if already added by scheduler
|
|
130
|
+
if database_added_by_scheduler:
|
|
131
|
+
continue
|
|
132
|
+
|
|
133
|
+
# Standard database prompt (when not added by scheduler)
|
|
134
|
+
prompt = f" Add {component_spec.description}?"
|
|
135
|
+
if typer.confirm(prompt):
|
|
136
|
+
selected.append("database")
|
|
137
|
+
|
|
138
|
+
# Show bonus backup job message when database added with scheduler
|
|
139
|
+
if "scheduler" in selected:
|
|
140
|
+
typer.echo("\nšÆ Bonus: Adding database backup job")
|
|
141
|
+
typer.echo(
|
|
142
|
+
"ā
Scheduled daily database backup job included (runs at 2 AM)"
|
|
143
|
+
)
|
|
144
|
+
else:
|
|
145
|
+
# Standard prompt for other components
|
|
146
|
+
prompt = f" Add {component_spec.description}?"
|
|
147
|
+
if typer.confirm(prompt):
|
|
148
|
+
selected.append(component_name)
|
|
149
|
+
|
|
150
|
+
# Update selected list with engine info for display
|
|
151
|
+
if "database" in selected and database_engine:
|
|
152
|
+
# Replace "database" with formatted version for display
|
|
153
|
+
db_index = selected.index("database")
|
|
154
|
+
selected[db_index] = f"database[{database_engine}]"
|
|
155
|
+
|
|
156
|
+
# Update scheduler with backend info if not memory
|
|
157
|
+
if "scheduler" in selected and scheduler_backend != "memory":
|
|
158
|
+
scheduler_index = selected.index("scheduler")
|
|
159
|
+
selected[scheduler_index] = f"scheduler[{scheduler_backend}]"
|
|
160
|
+
|
|
161
|
+
# Service selection
|
|
162
|
+
selected_services = []
|
|
163
|
+
|
|
164
|
+
if SERVICES: # Only show services if any are available
|
|
165
|
+
typer.echo("\nš§ Service Selection")
|
|
166
|
+
typer.echo("=" * 40)
|
|
167
|
+
typer.echo(
|
|
168
|
+
"Services provide business logic functionality for your application.\n"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Group services by type for better organization
|
|
172
|
+
auth_services = get_services_by_type(ServiceType.AUTH)
|
|
173
|
+
|
|
174
|
+
if auth_services:
|
|
175
|
+
typer.echo("š Authentication Services:")
|
|
176
|
+
for service_name, service_spec in auth_services.items():
|
|
177
|
+
prompt = f" Add {service_spec.description.lower()}?"
|
|
178
|
+
if typer.confirm(prompt):
|
|
179
|
+
# Auth service requires database - provide explicit confirmation
|
|
180
|
+
typer.echo("\nšļø Database Required:")
|
|
181
|
+
typer.echo(" Authentication requires a database for user storage")
|
|
182
|
+
typer.echo(" (user accounts, sessions, JWT tokens)")
|
|
183
|
+
|
|
184
|
+
# Check if database is already selected
|
|
185
|
+
database_already_selected = any(
|
|
186
|
+
"database" in comp for comp in selected
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
if database_already_selected:
|
|
190
|
+
typer.echo("ā
Database component already selected")
|
|
191
|
+
selected_services.append(service_name)
|
|
192
|
+
else:
|
|
193
|
+
auth_confirm_prompt = " Continue and add database component?"
|
|
194
|
+
if typer.confirm(auth_confirm_prompt, default=True):
|
|
195
|
+
selected_services.append(service_name)
|
|
196
|
+
# Note: Database will be auto-added by service resolution in init.py
|
|
197
|
+
typer.echo("ā
Authentication + Database configured")
|
|
198
|
+
else:
|
|
199
|
+
typer.echo("ā¹ļø Authentication service cancelled")
|
|
200
|
+
|
|
201
|
+
# AI & Machine Learning Services
|
|
202
|
+
ai_services = get_services_by_type(ServiceType.AI)
|
|
203
|
+
|
|
204
|
+
if ai_services:
|
|
205
|
+
typer.echo("\nš¤ AI & Machine Learning Services:")
|
|
206
|
+
for service_name, service_spec in ai_services.items():
|
|
207
|
+
prompt = f" Add {service_spec.description.lower()}?"
|
|
208
|
+
if typer.confirm(prompt):
|
|
209
|
+
# AI service requires backend (always available) - no dependency issues
|
|
210
|
+
typer.echo("\nš¤ AI Provider Selection:")
|
|
211
|
+
typer.echo(
|
|
212
|
+
" Choose AI providers to include (multiple selection supported)"
|
|
213
|
+
)
|
|
214
|
+
typer.echo(" š Provider Options:")
|
|
215
|
+
|
|
216
|
+
# Provider selection with recommendations
|
|
217
|
+
providers = []
|
|
218
|
+
provider_info = [
|
|
219
|
+
("openai", "OpenAI", "GPT models", "š° Paid", False),
|
|
220
|
+
("anthropic", "Anthropic", "Claude models", "š° Paid", False),
|
|
221
|
+
("google", "Google", "Gemini models", "š Free tier", True),
|
|
222
|
+
("groq", "Groq", "Fast inference", "š Free tier", True),
|
|
223
|
+
("mistral", "Mistral", "Open models", "š° Mostly paid", False),
|
|
224
|
+
(
|
|
225
|
+
"cohere",
|
|
226
|
+
"Cohere",
|
|
227
|
+
"Enterprise focus",
|
|
228
|
+
"š° Limited free",
|
|
229
|
+
False,
|
|
230
|
+
),
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
# Ask about each provider
|
|
234
|
+
for (
|
|
235
|
+
provider_id,
|
|
236
|
+
name,
|
|
237
|
+
description,
|
|
238
|
+
pricing,
|
|
239
|
+
recommended,
|
|
240
|
+
) in provider_info:
|
|
241
|
+
recommend_text = " (Recommended)" if recommended else ""
|
|
242
|
+
if typer.confirm(
|
|
243
|
+
f" ā {name} - {description} ({pricing}){recommend_text}?",
|
|
244
|
+
default=recommended,
|
|
245
|
+
):
|
|
246
|
+
providers.append(provider_id)
|
|
247
|
+
|
|
248
|
+
# Handle no providers selected
|
|
249
|
+
if not providers:
|
|
250
|
+
typer.echo(
|
|
251
|
+
" ā ļø No providers selected, adding recommended defaults..."
|
|
252
|
+
)
|
|
253
|
+
providers = ["groq", "google"] # Safe defaults with free tiers
|
|
254
|
+
|
|
255
|
+
# Show selected providers
|
|
256
|
+
typer.echo(f"\n ā
Selected providers: {', '.join(providers)}")
|
|
257
|
+
typer.echo(" š¦ Dependencies will be optimized for your selection")
|
|
258
|
+
|
|
259
|
+
# Store provider selection in global context for template generation
|
|
260
|
+
_ai_provider_selection[service_name] = providers
|
|
261
|
+
selected_services.append(service_name)
|
|
262
|
+
typer.echo("ā
AI service configured")
|
|
263
|
+
|
|
264
|
+
# Future service types can be added here as they become available
|
|
265
|
+
# payment_services = get_services_by_type(ServiceType.PAYMENT)
|
|
266
|
+
|
|
267
|
+
return selected, scheduler_backend, selected_services
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def get_ai_provider_selection(service_name: str = "ai") -> list[str]:
|
|
271
|
+
"""
|
|
272
|
+
Get AI provider selection from interactive session.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
service_name: Name of the AI service (defaults to "ai")
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
List of selected provider names, or default providers if none selected
|
|
279
|
+
"""
|
|
280
|
+
return _ai_provider_selection.get(service_name, ["openai"])
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def clear_ai_provider_selection() -> None:
|
|
284
|
+
"""Clear stored AI provider selection (useful for testing)."""
|
|
285
|
+
global _ai_provider_selection
|
|
286
|
+
_ai_provider_selection.clear()
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def interactive_component_add_selection(project_path: Path) -> tuple[list[str], str]:
|
|
290
|
+
"""
|
|
291
|
+
Interactive component selection for adding to existing project.
|
|
292
|
+
|
|
293
|
+
Shows currently enabled components (grayed out) and available
|
|
294
|
+
components to add (selectable). Handles dependency resolution.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
project_path: Path to the existing project
|
|
298
|
+
|
|
299
|
+
Returns:
|
|
300
|
+
Tuple of (selected_components, scheduler_backend)
|
|
301
|
+
"""
|
|
302
|
+
from ..core.copier_manager import load_copier_answers
|
|
303
|
+
|
|
304
|
+
# Load current project state
|
|
305
|
+
try:
|
|
306
|
+
current_answers = load_copier_answers(project_path)
|
|
307
|
+
except Exception as e:
|
|
308
|
+
typer.echo(f"ā Failed to load project configuration: {e}", err=True)
|
|
309
|
+
raise typer.Exit(1)
|
|
310
|
+
|
|
311
|
+
typer.echo("\nšÆ Component Selection")
|
|
312
|
+
typer.echo("=" * 40)
|
|
313
|
+
|
|
314
|
+
# Show currently enabled components
|
|
315
|
+
enabled_components = []
|
|
316
|
+
for component in ["redis", "worker", "scheduler", "database"]:
|
|
317
|
+
if current_answers.get(f"include_{component}"):
|
|
318
|
+
enabled_components.append(component)
|
|
319
|
+
|
|
320
|
+
if enabled_components:
|
|
321
|
+
typer.echo(f"ā
Currently enabled: {', '.join(enabled_components)}")
|
|
322
|
+
else:
|
|
323
|
+
typer.echo("ā
Currently enabled: backend, frontend (core only)")
|
|
324
|
+
|
|
325
|
+
typer.echo("\nšļø Available Components:\n")
|
|
326
|
+
|
|
327
|
+
selected = []
|
|
328
|
+
scheduler_backend = "memory"
|
|
329
|
+
|
|
330
|
+
# Get all infrastructure components in order
|
|
331
|
+
component_order = ["redis", "worker", "scheduler", "database"]
|
|
332
|
+
|
|
333
|
+
for component_name in component_order:
|
|
334
|
+
# Skip if already enabled
|
|
335
|
+
if component_name in enabled_components:
|
|
336
|
+
typer.echo(f" ā
{component_name} - Already enabled")
|
|
337
|
+
continue
|
|
338
|
+
|
|
339
|
+
# Skip if already selected in this session (e.g., database auto-added by scheduler)
|
|
340
|
+
if component_name in selected:
|
|
341
|
+
continue
|
|
342
|
+
|
|
343
|
+
# Find the component spec
|
|
344
|
+
component_spec = COMPONENTS.get(component_name)
|
|
345
|
+
if not component_spec:
|
|
346
|
+
continue
|
|
347
|
+
|
|
348
|
+
# Handle special logic for each component
|
|
349
|
+
if component_name == "worker":
|
|
350
|
+
if "redis" in enabled_components or "redis" in selected:
|
|
351
|
+
# Redis already available
|
|
352
|
+
prompt = f" Add {component_spec.description.lower()}?"
|
|
353
|
+
if typer.confirm(prompt):
|
|
354
|
+
selected.append("worker")
|
|
355
|
+
else:
|
|
356
|
+
# Need to add redis too
|
|
357
|
+
prompt = (
|
|
358
|
+
f" Add {component_spec.description.lower()}? (will auto-add Redis)"
|
|
359
|
+
)
|
|
360
|
+
if typer.confirm(prompt):
|
|
361
|
+
selected.extend(["redis", "worker"])
|
|
362
|
+
|
|
363
|
+
elif component_name == "scheduler":
|
|
364
|
+
prompt = f" Add {component_spec.description}?"
|
|
365
|
+
if typer.confirm(prompt):
|
|
366
|
+
selected.append("scheduler")
|
|
367
|
+
|
|
368
|
+
# Check if database is available or will be added
|
|
369
|
+
database_available = (
|
|
370
|
+
"database" in enabled_components or "database" in selected
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
if database_available:
|
|
374
|
+
# Database already available - offer persistence
|
|
375
|
+
typer.echo("\nš¾ Scheduler Persistence:")
|
|
376
|
+
if typer.confirm(" Enable job persistence with SQLite?"):
|
|
377
|
+
scheduler_backend = "sqlite"
|
|
378
|
+
typer.echo(" ā
Scheduler will use SQLite for job persistence")
|
|
379
|
+
else:
|
|
380
|
+
typer.echo(
|
|
381
|
+
" ā¹ļø Scheduler will use memory backend (no persistence)"
|
|
382
|
+
)
|
|
383
|
+
else:
|
|
384
|
+
# Ask if they plan to add database
|
|
385
|
+
typer.echo("\nš¾ Scheduler Persistence:")
|
|
386
|
+
typer.echo(" Job persistence requires SQLite database component")
|
|
387
|
+
if typer.confirm(" Add database component for job persistence?"):
|
|
388
|
+
selected.append("database")
|
|
389
|
+
scheduler_backend = "sqlite"
|
|
390
|
+
typer.echo(
|
|
391
|
+
" ā
Database will be added - scheduler will use SQLite"
|
|
392
|
+
)
|
|
393
|
+
else:
|
|
394
|
+
typer.echo(
|
|
395
|
+
" ā¹ļø Scheduler will use memory backend (no persistence)"
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
elif component_name == "redis":
|
|
399
|
+
# Only offer if not already added by worker
|
|
400
|
+
if "redis" not in selected:
|
|
401
|
+
prompt = f" Add {component_spec.description}?"
|
|
402
|
+
if typer.confirm(prompt):
|
|
403
|
+
selected.append("redis")
|
|
404
|
+
|
|
405
|
+
else:
|
|
406
|
+
# Standard prompt for other components
|
|
407
|
+
prompt = f" Add {component_spec.description}?"
|
|
408
|
+
if typer.confirm(prompt):
|
|
409
|
+
selected.append(component_name)
|
|
410
|
+
|
|
411
|
+
return selected, scheduler_backend
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def interactive_component_remove_selection(project_path: Path) -> list[str]:
|
|
415
|
+
"""
|
|
416
|
+
Interactive component selection for removing from project.
|
|
417
|
+
|
|
418
|
+
Shows currently enabled components (selectable) and core components
|
|
419
|
+
(grayed out, cannot remove). Displays deletion warnings.
|
|
420
|
+
|
|
421
|
+
Args:
|
|
422
|
+
project_path: Path to the existing project
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
List of components to remove
|
|
426
|
+
"""
|
|
427
|
+
from ..core.copier_manager import load_copier_answers
|
|
428
|
+
|
|
429
|
+
# Load current project state
|
|
430
|
+
try:
|
|
431
|
+
current_answers = load_copier_answers(project_path)
|
|
432
|
+
except Exception as e:
|
|
433
|
+
typer.echo(f"ā Failed to load project configuration: {e}", err=True)
|
|
434
|
+
raise typer.Exit(1)
|
|
435
|
+
|
|
436
|
+
typer.echo("\nā ļø Component Removal")
|
|
437
|
+
typer.echo("=" * 40)
|
|
438
|
+
typer.echo("ā ļø WARNING: This will DELETE component files from your project!")
|
|
439
|
+
typer.echo()
|
|
440
|
+
|
|
441
|
+
# Find enabled components
|
|
442
|
+
enabled_removable = []
|
|
443
|
+
for component in ["redis", "worker", "scheduler", "database"]:
|
|
444
|
+
if current_answers.get(f"include_{component}"):
|
|
445
|
+
enabled_removable.append(component)
|
|
446
|
+
|
|
447
|
+
if not enabled_removable:
|
|
448
|
+
typer.echo("ā¹ļø No optional components to remove")
|
|
449
|
+
typer.echo(" (Core components backend + frontend cannot be removed)")
|
|
450
|
+
return []
|
|
451
|
+
|
|
452
|
+
typer.echo("Currently enabled components:\n")
|
|
453
|
+
|
|
454
|
+
# Show core components (not removable)
|
|
455
|
+
typer.echo(" āŖ backend - Core component (cannot remove)")
|
|
456
|
+
typer.echo(" āŖ frontend - Core component (cannot remove)")
|
|
457
|
+
typer.echo()
|
|
458
|
+
|
|
459
|
+
# Show removable components
|
|
460
|
+
selected = []
|
|
461
|
+
for component_name in enabled_removable:
|
|
462
|
+
component_spec = COMPONENTS.get(component_name)
|
|
463
|
+
if component_spec:
|
|
464
|
+
prompt = f" Remove {component_spec.description.lower()}?"
|
|
465
|
+
if typer.confirm(prompt):
|
|
466
|
+
selected.append(component_name)
|
|
467
|
+
|
|
468
|
+
return selected
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def interactive_service_selection(project_path: Path) -> list[str]:
|
|
472
|
+
"""
|
|
473
|
+
Interactive service selection for adding to existing project.
|
|
474
|
+
|
|
475
|
+
Shows available services with their descriptions and required components.
|
|
476
|
+
Warns if required components are missing.
|
|
477
|
+
|
|
478
|
+
Args:
|
|
479
|
+
project_path: Path to the existing project
|
|
480
|
+
|
|
481
|
+
Returns:
|
|
482
|
+
List of services to add
|
|
483
|
+
"""
|
|
484
|
+
from ..core.copier_manager import load_copier_answers
|
|
485
|
+
|
|
486
|
+
# Load current project state
|
|
487
|
+
try:
|
|
488
|
+
current_answers = load_copier_answers(project_path)
|
|
489
|
+
except Exception as e:
|
|
490
|
+
typer.echo(f"ā Failed to load project configuration: {e}", err=True)
|
|
491
|
+
raise typer.Exit(1)
|
|
492
|
+
|
|
493
|
+
typer.echo("\nš§ Service Selection")
|
|
494
|
+
typer.echo("=" * 40)
|
|
495
|
+
typer.echo("Services provide business logic functionality for your application.\n")
|
|
496
|
+
|
|
497
|
+
# Find already enabled services
|
|
498
|
+
enabled_services = []
|
|
499
|
+
for service_name in SERVICES:
|
|
500
|
+
if current_answers.get(f"include_{service_name}"):
|
|
501
|
+
enabled_services.append(service_name)
|
|
502
|
+
|
|
503
|
+
# Find enabled components
|
|
504
|
+
enabled_components = set(CORE_COMPONENTS) # Always have core components
|
|
505
|
+
for component in ["redis", "worker", "scheduler", "database"]:
|
|
506
|
+
if current_answers.get(f"include_{component}"):
|
|
507
|
+
enabled_components.add(component)
|
|
508
|
+
|
|
509
|
+
if enabled_services:
|
|
510
|
+
typer.echo("Currently enabled services:")
|
|
511
|
+
for service_name in enabled_services:
|
|
512
|
+
service_spec = SERVICES[service_name]
|
|
513
|
+
typer.echo(f" ā
{service_name}: {service_spec.description}")
|
|
514
|
+
typer.echo()
|
|
515
|
+
|
|
516
|
+
# Show available services grouped by type
|
|
517
|
+
selected_services = []
|
|
518
|
+
|
|
519
|
+
# Authentication Services
|
|
520
|
+
auth_services = get_services_by_type(ServiceType.AUTH)
|
|
521
|
+
if auth_services:
|
|
522
|
+
typer.echo("š Authentication Services:")
|
|
523
|
+
for service_name, service_spec in auth_services.items():
|
|
524
|
+
# Skip if already enabled
|
|
525
|
+
if service_name in enabled_services:
|
|
526
|
+
typer.echo(f" ā
{service_name} - Already enabled")
|
|
527
|
+
continue
|
|
528
|
+
|
|
529
|
+
# Check component requirements
|
|
530
|
+
missing_components = [
|
|
531
|
+
comp
|
|
532
|
+
for comp in service_spec.required_components
|
|
533
|
+
if comp not in enabled_components
|
|
534
|
+
]
|
|
535
|
+
|
|
536
|
+
if missing_components:
|
|
537
|
+
requirement_text = f" (will auto-add: {', '.join(missing_components)})"
|
|
538
|
+
else:
|
|
539
|
+
requirement_text = ""
|
|
540
|
+
|
|
541
|
+
prompt = f" Add {service_spec.description.lower()}{requirement_text}?"
|
|
542
|
+
if typer.confirm(prompt):
|
|
543
|
+
selected_services.append(service_name)
|
|
544
|
+
|
|
545
|
+
if missing_components:
|
|
546
|
+
typer.echo(
|
|
547
|
+
f" š¦ Required components will be added: {', '.join(missing_components)}"
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
# AI & Machine Learning Services
|
|
551
|
+
ai_services = get_services_by_type(ServiceType.AI)
|
|
552
|
+
if ai_services:
|
|
553
|
+
typer.echo("\nš¤ AI & Machine Learning Services:")
|
|
554
|
+
for service_name, service_spec in ai_services.items():
|
|
555
|
+
# Skip if already enabled
|
|
556
|
+
if service_name in enabled_services:
|
|
557
|
+
typer.echo(f" ā
{service_name} - Already enabled")
|
|
558
|
+
continue
|
|
559
|
+
|
|
560
|
+
# Check component requirements
|
|
561
|
+
missing_components = [
|
|
562
|
+
comp
|
|
563
|
+
for comp in service_spec.required_components
|
|
564
|
+
if comp not in enabled_components
|
|
565
|
+
]
|
|
566
|
+
|
|
567
|
+
if missing_components:
|
|
568
|
+
requirement_text = f" (will auto-add: {', '.join(missing_components)})"
|
|
569
|
+
else:
|
|
570
|
+
requirement_text = ""
|
|
571
|
+
|
|
572
|
+
prompt = f" Add {service_spec.description.lower()}{requirement_text}?"
|
|
573
|
+
if typer.confirm(prompt):
|
|
574
|
+
selected_services.append(service_name)
|
|
575
|
+
|
|
576
|
+
if missing_components:
|
|
577
|
+
typer.echo(
|
|
578
|
+
f" š¦ Required components will be added: {', '.join(missing_components)}"
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
# Payment Services (when they exist)
|
|
582
|
+
payment_services = get_services_by_type(ServiceType.PAYMENT)
|
|
583
|
+
if payment_services:
|
|
584
|
+
typer.echo("\nš° Payment Services:")
|
|
585
|
+
for service_name, service_spec in payment_services.items():
|
|
586
|
+
if service_name in enabled_services:
|
|
587
|
+
typer.echo(f" ā
{service_name} - Already enabled")
|
|
588
|
+
continue
|
|
589
|
+
|
|
590
|
+
missing_components = [
|
|
591
|
+
comp
|
|
592
|
+
for comp in service_spec.required_components
|
|
593
|
+
if comp not in enabled_components
|
|
594
|
+
]
|
|
595
|
+
|
|
596
|
+
requirement_text = (
|
|
597
|
+
f" (will auto-add: {', '.join(missing_components)})"
|
|
598
|
+
if missing_components
|
|
599
|
+
else ""
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
prompt = f" Add {service_spec.description.lower()}{requirement_text}?"
|
|
603
|
+
if typer.confirm(prompt):
|
|
604
|
+
selected_services.append(service_name)
|
|
605
|
+
|
|
606
|
+
if missing_components:
|
|
607
|
+
typer.echo(
|
|
608
|
+
f" š¦ Required components will be added: {', '.join(missing_components)}"
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
return selected_services
|
aegis/cli/utils.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI utility functions.
|
|
3
|
+
|
|
4
|
+
This module contains utility functions used by CLI commands for
|
|
5
|
+
component detection, dependency expansion, and other common tasks.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from ..core.component_utils import (
|
|
11
|
+
clean_component_names,
|
|
12
|
+
extract_base_component_name,
|
|
13
|
+
extract_engine_info,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def detect_scheduler_backend(components: list[str]) -> str:
|
|
18
|
+
"""
|
|
19
|
+
Detect scheduler backend from component list.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
components: List of component names, possibly including scheduler[backend]
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Backend name: "memory", "sqlite", or "postgres"
|
|
26
|
+
"""
|
|
27
|
+
for component in components:
|
|
28
|
+
base_name = extract_base_component_name(component)
|
|
29
|
+
if base_name == "scheduler":
|
|
30
|
+
engine = extract_engine_info(component)
|
|
31
|
+
if engine:
|
|
32
|
+
# Direct scheduler[backend] syntax
|
|
33
|
+
return engine
|
|
34
|
+
else:
|
|
35
|
+
# Check if database is also present (legacy detection)
|
|
36
|
+
clean_names = clean_component_names(components)
|
|
37
|
+
if "database" in clean_names:
|
|
38
|
+
return "sqlite" # Default database backend
|
|
39
|
+
return "memory" # Default to memory-only
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def expand_scheduler_dependencies(components: list[str]) -> list[str]:
|
|
43
|
+
"""
|
|
44
|
+
Expand scheduler[backend] to include required database dependencies.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
components: List of component names
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Expanded component list with auto-added dependencies
|
|
51
|
+
"""
|
|
52
|
+
result = list(components) # Copy the list
|
|
53
|
+
|
|
54
|
+
for component in components:
|
|
55
|
+
base_name = extract_base_component_name(component)
|
|
56
|
+
if base_name == "scheduler":
|
|
57
|
+
backend = extract_engine_info(component)
|
|
58
|
+
if backend and backend != "memory":
|
|
59
|
+
# Auto-add database with same backend if not already present
|
|
60
|
+
database_component = f"database[{backend}]"
|
|
61
|
+
existing_clean = clean_component_names(result)
|
|
62
|
+
|
|
63
|
+
if "database" not in existing_clean:
|
|
64
|
+
result.append(database_component)
|
|
65
|
+
typer.echo(
|
|
66
|
+
f"š¦ Auto-added database[{backend}] for "
|
|
67
|
+
f"scheduler[{backend}] persistence"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return result
|