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/commands/init.py
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Init command implementation.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import cast
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from ..cli.callbacks import (
|
|
11
|
+
validate_and_resolve_components,
|
|
12
|
+
validate_and_resolve_services,
|
|
13
|
+
)
|
|
14
|
+
from ..cli.interactive import interactive_project_selection
|
|
15
|
+
from ..cli.utils import detect_scheduler_backend
|
|
16
|
+
from ..cli.validators import validate_project_name
|
|
17
|
+
from ..core.component_utils import (
|
|
18
|
+
clean_component_names,
|
|
19
|
+
extract_base_component_name,
|
|
20
|
+
restore_engine_info,
|
|
21
|
+
)
|
|
22
|
+
from ..core.components import (
|
|
23
|
+
COMPONENTS,
|
|
24
|
+
CORE_COMPONENTS,
|
|
25
|
+
ComponentType,
|
|
26
|
+
SchedulerBackend,
|
|
27
|
+
)
|
|
28
|
+
from ..core.dependency_resolver import DependencyResolver
|
|
29
|
+
from ..core.service_resolver import ServiceResolver
|
|
30
|
+
from ..core.template_generator import TemplateGenerator
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def init_command(
|
|
34
|
+
project_name: str = typer.Argument(
|
|
35
|
+
..., help="Name of the new Aegis Stack project to create"
|
|
36
|
+
),
|
|
37
|
+
components: str | None = typer.Option(
|
|
38
|
+
None,
|
|
39
|
+
"--components",
|
|
40
|
+
"-c",
|
|
41
|
+
callback=validate_and_resolve_components,
|
|
42
|
+
help="Comma-separated list of components (redis,worker,scheduler,database)",
|
|
43
|
+
),
|
|
44
|
+
services: str | None = typer.Option(
|
|
45
|
+
None,
|
|
46
|
+
"--services",
|
|
47
|
+
"-s",
|
|
48
|
+
callback=validate_and_resolve_services,
|
|
49
|
+
help="Comma-separated list of services (auth). Use 'aegis services' for full list.",
|
|
50
|
+
),
|
|
51
|
+
interactive: bool = typer.Option(
|
|
52
|
+
True,
|
|
53
|
+
"--interactive/--no-interactive",
|
|
54
|
+
"-i/-ni",
|
|
55
|
+
help="Use interactive component selection",
|
|
56
|
+
),
|
|
57
|
+
force: bool = typer.Option(
|
|
58
|
+
False, "--force", "-f", help="Overwrite existing directory if it exists"
|
|
59
|
+
),
|
|
60
|
+
output_dir: str | None = typer.Option(
|
|
61
|
+
None,
|
|
62
|
+
"--output-dir",
|
|
63
|
+
"-o",
|
|
64
|
+
help="Directory to create the project in (default: current directory)",
|
|
65
|
+
),
|
|
66
|
+
yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt"),
|
|
67
|
+
engine: str = typer.Option(
|
|
68
|
+
"copier",
|
|
69
|
+
"--engine",
|
|
70
|
+
hidden=True, # Internal testing flag, not shown in --help
|
|
71
|
+
help="Template engine (cookiecutter or copier) - for internal testing",
|
|
72
|
+
),
|
|
73
|
+
) -> None:
|
|
74
|
+
"""
|
|
75
|
+
Initialize a new Aegis Stack project with battle-tested component combinations.
|
|
76
|
+
|
|
77
|
+
This command creates a complete project structure with your chosen components,
|
|
78
|
+
ensuring all dependencies and configurations are compatible and tested.
|
|
79
|
+
|
|
80
|
+
Examples:\\n
|
|
81
|
+
- aegis init my-app\\n
|
|
82
|
+
- aegis init my-app --components redis,worker\\n
|
|
83
|
+
- aegis init my-app --components redis,worker,scheduler,database --no-interactive\\n
|
|
84
|
+
- aegis init my-app --services auth --no-interactive\\n
|
|
85
|
+
""" # noqa
|
|
86
|
+
|
|
87
|
+
# Validate project name first
|
|
88
|
+
validate_project_name(project_name)
|
|
89
|
+
|
|
90
|
+
# Validate engine parameter
|
|
91
|
+
valid_engines = ["cookiecutter", "copier"]
|
|
92
|
+
if engine not in valid_engines:
|
|
93
|
+
typer.echo(
|
|
94
|
+
f"❌ Invalid engine '{engine}'. Must be one of: {', '.join(valid_engines)}",
|
|
95
|
+
err=True,
|
|
96
|
+
)
|
|
97
|
+
raise typer.Exit(1)
|
|
98
|
+
|
|
99
|
+
typer.echo("🛡️ Aegis Stack Project Initialization")
|
|
100
|
+
typer.echo("=" * 50)
|
|
101
|
+
|
|
102
|
+
# Determine output directory
|
|
103
|
+
base_output_dir = Path(output_dir) if output_dir else Path.cwd()
|
|
104
|
+
project_path = base_output_dir / project_name
|
|
105
|
+
|
|
106
|
+
typer.echo(f"📁 Project will be created in: {project_path.resolve()}")
|
|
107
|
+
|
|
108
|
+
# Check if directory already exists
|
|
109
|
+
if project_path.exists():
|
|
110
|
+
if not force:
|
|
111
|
+
typer.echo(f"❌ Directory '{project_path}' already exists", err=True)
|
|
112
|
+
typer.echo(
|
|
113
|
+
" Use --force to overwrite or choose a different name", err=True
|
|
114
|
+
)
|
|
115
|
+
raise typer.Exit(1)
|
|
116
|
+
else:
|
|
117
|
+
typer.echo(f"⚠️ Overwriting existing directory: {project_path}")
|
|
118
|
+
|
|
119
|
+
# Interactive component selection
|
|
120
|
+
# Note: components is list[str] after callback, despite str annotation
|
|
121
|
+
selected_components = cast(list[str], components) if components else []
|
|
122
|
+
selected_services = cast(list[str], services) if services else []
|
|
123
|
+
scheduler_backend = SchedulerBackend.MEMORY.value # Default to in-memory scheduler
|
|
124
|
+
|
|
125
|
+
# Resolve services to components if services were provided (non-interactive mode only)
|
|
126
|
+
if selected_services and not interactive:
|
|
127
|
+
# Check if --components was explicitly provided
|
|
128
|
+
components_explicitly_provided = components is not None
|
|
129
|
+
|
|
130
|
+
if components_explicitly_provided:
|
|
131
|
+
# In non-interactive mode with explicit --components, validate compatibility
|
|
132
|
+
# Include core components (always present) for validation
|
|
133
|
+
components_for_validation = list(set(selected_components + CORE_COMPONENTS))
|
|
134
|
+
errors = ServiceResolver.validate_service_component_compatibility(
|
|
135
|
+
selected_services, components_for_validation
|
|
136
|
+
)
|
|
137
|
+
if errors:
|
|
138
|
+
typer.echo("❌ Service-component compatibility errors:", err=True)
|
|
139
|
+
for error in errors:
|
|
140
|
+
typer.echo(f" • {error}", err=True)
|
|
141
|
+
|
|
142
|
+
# Show suggestion
|
|
143
|
+
missing_components = (
|
|
144
|
+
ServiceResolver.get_missing_components_for_services(
|
|
145
|
+
selected_services, components_for_validation
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
if missing_components:
|
|
149
|
+
typer.echo(
|
|
150
|
+
f"💡 Suggestion: Add missing components --components {','.join(sorted(set(selected_components + missing_components)))}",
|
|
151
|
+
err=True,
|
|
152
|
+
)
|
|
153
|
+
typer.echo(
|
|
154
|
+
" Or remove --components to let services auto-add dependencies.",
|
|
155
|
+
err=True,
|
|
156
|
+
)
|
|
157
|
+
typer.echo(
|
|
158
|
+
" Alternatively, use interactive mode to auto-add service dependencies.",
|
|
159
|
+
err=True,
|
|
160
|
+
)
|
|
161
|
+
raise typer.Exit(1)
|
|
162
|
+
else:
|
|
163
|
+
# No --components provided, auto-add required components for services
|
|
164
|
+
service_components, _ = ServiceResolver.resolve_service_dependencies(
|
|
165
|
+
selected_services
|
|
166
|
+
)
|
|
167
|
+
if service_components:
|
|
168
|
+
typer.echo(
|
|
169
|
+
f"📦 Services require components: {', '.join(sorted(service_components))}"
|
|
170
|
+
)
|
|
171
|
+
selected_components = service_components
|
|
172
|
+
|
|
173
|
+
# Resolve service dependencies and merge with any explicitly selected components
|
|
174
|
+
service_components, _ = ServiceResolver.resolve_service_dependencies(
|
|
175
|
+
selected_services
|
|
176
|
+
)
|
|
177
|
+
# Merge service-required components with explicitly selected components
|
|
178
|
+
all_components = list(set(selected_components + service_components))
|
|
179
|
+
selected_components = all_components
|
|
180
|
+
|
|
181
|
+
# Auto-detect scheduler backend when components are specified
|
|
182
|
+
if selected_components:
|
|
183
|
+
scheduler_backend = detect_scheduler_backend(selected_components)
|
|
184
|
+
if scheduler_backend != SchedulerBackend.MEMORY.value:
|
|
185
|
+
typer.echo(
|
|
186
|
+
f"📊 Auto-detected: Scheduler with {scheduler_backend} persistence"
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
if interactive and not components and not services:
|
|
190
|
+
selected_components, scheduler_backend, interactive_services = (
|
|
191
|
+
interactive_project_selection()
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Resolve dependencies for interactively selected components
|
|
195
|
+
if selected_components:
|
|
196
|
+
# Clean component names for dependency resolution (remove engine info)
|
|
197
|
+
# Save original with engine info
|
|
198
|
+
original_selected = list(selected_components)
|
|
199
|
+
clean_components = clean_component_names(selected_components)
|
|
200
|
+
|
|
201
|
+
resolved_clean = DependencyResolver.resolve_dependencies(clean_components)
|
|
202
|
+
|
|
203
|
+
# Restore engine info for display components
|
|
204
|
+
selected_components = restore_engine_info(resolved_clean, original_selected)
|
|
205
|
+
|
|
206
|
+
# Calculate auto-added components using clean names
|
|
207
|
+
clean_selected_only = clean_component_names(
|
|
208
|
+
[c for c in selected_components if c not in CORE_COMPONENTS]
|
|
209
|
+
)
|
|
210
|
+
auto_added = DependencyResolver.get_missing_dependencies(
|
|
211
|
+
clean_selected_only
|
|
212
|
+
)
|
|
213
|
+
if auto_added:
|
|
214
|
+
typer.echo(f"\n📦 Auto-added dependencies: {', '.join(auto_added)}")
|
|
215
|
+
|
|
216
|
+
# Merge interactively selected services with any already selected services
|
|
217
|
+
selected_services = list(set(selected_services + interactive_services))
|
|
218
|
+
|
|
219
|
+
# Handle service dependencies for interactively selected services
|
|
220
|
+
if interactive_services:
|
|
221
|
+
# Track originally selected components before service resolution
|
|
222
|
+
originally_selected_components = selected_components.copy()
|
|
223
|
+
|
|
224
|
+
service_components, _ = ServiceResolver.resolve_service_dependencies(
|
|
225
|
+
interactive_services
|
|
226
|
+
)
|
|
227
|
+
# Merge service-required components with selected components
|
|
228
|
+
all_components = list(set(selected_components + service_components))
|
|
229
|
+
selected_components = all_components
|
|
230
|
+
|
|
231
|
+
# Show which components were auto-added by services
|
|
232
|
+
service_added_components = [
|
|
233
|
+
comp
|
|
234
|
+
for comp in service_components
|
|
235
|
+
if comp not in originally_selected_components
|
|
236
|
+
and comp not in CORE_COMPONENTS
|
|
237
|
+
]
|
|
238
|
+
if service_added_components:
|
|
239
|
+
# Create a mapping of which services require which components
|
|
240
|
+
service_component_map = {}
|
|
241
|
+
for service_name in interactive_services:
|
|
242
|
+
service_deps = ServiceResolver.resolve_service_dependencies(
|
|
243
|
+
[service_name]
|
|
244
|
+
)[0]
|
|
245
|
+
for comp in service_deps:
|
|
246
|
+
if comp in service_added_components:
|
|
247
|
+
if comp not in service_component_map:
|
|
248
|
+
service_component_map[comp] = []
|
|
249
|
+
service_component_map[comp].append(service_name)
|
|
250
|
+
|
|
251
|
+
typer.echo("\n📦 Auto-added by services:")
|
|
252
|
+
for comp, requiring_services in service_component_map.items():
|
|
253
|
+
services_str = ", ".join(requiring_services)
|
|
254
|
+
typer.echo(f" • {comp} (required by {services_str})")
|
|
255
|
+
|
|
256
|
+
# Create template generator with scheduler backend context
|
|
257
|
+
template_gen = TemplateGenerator(
|
|
258
|
+
project_name, list(selected_components), scheduler_backend, selected_services
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
# Show selected configuration
|
|
262
|
+
typer.echo()
|
|
263
|
+
typer.echo(f"📁 Project Name: {project_name}")
|
|
264
|
+
typer.echo("🏗️ Project Structure:")
|
|
265
|
+
typer.echo(f" ✅ Core: {', '.join(CORE_COMPONENTS)}")
|
|
266
|
+
|
|
267
|
+
# Show infrastructure components
|
|
268
|
+
infra_components = []
|
|
269
|
+
for name in selected_components:
|
|
270
|
+
# Handle database[engine] format
|
|
271
|
+
base_name = extract_base_component_name(name)
|
|
272
|
+
if (
|
|
273
|
+
base_name in COMPONENTS
|
|
274
|
+
and COMPONENTS[base_name].type == ComponentType.INFRASTRUCTURE
|
|
275
|
+
):
|
|
276
|
+
infra_components.append(name)
|
|
277
|
+
|
|
278
|
+
if infra_components:
|
|
279
|
+
typer.echo(f" 📦 Infrastructure: {', '.join(infra_components)}")
|
|
280
|
+
|
|
281
|
+
# Show selected services
|
|
282
|
+
if selected_services:
|
|
283
|
+
typer.echo(f" 🔧 Services: {', '.join(selected_services)}")
|
|
284
|
+
|
|
285
|
+
# Show template files that will be generated
|
|
286
|
+
template_files = template_gen.get_template_files()
|
|
287
|
+
if template_files:
|
|
288
|
+
typer.echo("\n📄 Component Files:")
|
|
289
|
+
for file_path in template_files:
|
|
290
|
+
typer.echo(f" • {file_path}")
|
|
291
|
+
|
|
292
|
+
# Show entrypoints that will be created
|
|
293
|
+
entrypoints = template_gen.get_entrypoints()
|
|
294
|
+
if entrypoints:
|
|
295
|
+
typer.echo("\n🚀 Entrypoints:")
|
|
296
|
+
for entrypoint in entrypoints:
|
|
297
|
+
typer.echo(f" • {entrypoint}")
|
|
298
|
+
|
|
299
|
+
# Show worker queues that will be created
|
|
300
|
+
worker_queues = template_gen.get_worker_queues()
|
|
301
|
+
if worker_queues:
|
|
302
|
+
typer.echo("\n👷 Worker Queues:")
|
|
303
|
+
for queue in worker_queues:
|
|
304
|
+
typer.echo(f" • {queue}")
|
|
305
|
+
|
|
306
|
+
# Show dependency information using template generator
|
|
307
|
+
deps = template_gen._get_pyproject_deps()
|
|
308
|
+
if deps:
|
|
309
|
+
typer.echo("\n📦 Dependencies to be installed:")
|
|
310
|
+
for dep in deps:
|
|
311
|
+
typer.echo(f" • {dep}")
|
|
312
|
+
|
|
313
|
+
# Confirm before proceeding
|
|
314
|
+
typer.echo()
|
|
315
|
+
if not yes and not typer.confirm("🚀 Create this project?"):
|
|
316
|
+
typer.echo("❌ Project creation cancelled")
|
|
317
|
+
raise typer.Exit(0)
|
|
318
|
+
|
|
319
|
+
# Handle force overwrite by completely removing existing directory
|
|
320
|
+
project_path = base_output_dir / project_name
|
|
321
|
+
if force and project_path.exists():
|
|
322
|
+
typer.echo(f"🗑️ Removing existing directory: {project_path}")
|
|
323
|
+
import shutil
|
|
324
|
+
|
|
325
|
+
shutil.rmtree(project_path)
|
|
326
|
+
|
|
327
|
+
# Create project using selected template engine
|
|
328
|
+
typer.echo()
|
|
329
|
+
typer.echo(f"🔧 Creating project: {project_name}")
|
|
330
|
+
|
|
331
|
+
try:
|
|
332
|
+
if engine == "copier":
|
|
333
|
+
# Use Copier template engine
|
|
334
|
+
from ..core.copier_manager import generate_with_copier
|
|
335
|
+
|
|
336
|
+
generate_with_copier(template_gen, base_output_dir)
|
|
337
|
+
|
|
338
|
+
else:
|
|
339
|
+
# Use Cookiecutter template engine (fallback option)
|
|
340
|
+
from cookiecutter.main import cookiecutter
|
|
341
|
+
|
|
342
|
+
# Get the template path
|
|
343
|
+
template_path = (
|
|
344
|
+
Path(__file__).parent.parent
|
|
345
|
+
/ "templates"
|
|
346
|
+
/ "cookiecutter-aegis-project"
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
# Use template generator for context
|
|
350
|
+
extra_context = template_gen.get_template_context()
|
|
351
|
+
|
|
352
|
+
# Generate project with cookiecutter
|
|
353
|
+
cookiecutter(
|
|
354
|
+
str(template_path),
|
|
355
|
+
extra_context=extra_context,
|
|
356
|
+
output_dir=str(base_output_dir),
|
|
357
|
+
no_input=True, # Don't prompt user, use our context
|
|
358
|
+
overwrite_if_exists=False, # No longer needed since we remove directory first
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
# Note: Comprehensive setup output is now handled by the post-generation hook
|
|
362
|
+
# which provides better status reporting and automated setup
|
|
363
|
+
|
|
364
|
+
except ImportError as e:
|
|
365
|
+
typer.echo(f"❌ Error: {e}", err=True)
|
|
366
|
+
typer.echo(" Required template engine not installed", err=True)
|
|
367
|
+
raise typer.Exit(1)
|
|
368
|
+
except Exception as e:
|
|
369
|
+
typer.echo(f"❌ Error creating project: {e}", err=True)
|
|
370
|
+
raise typer.Exit(1)
|
aegis/commands/remove.py
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Remove command implementation.
|
|
3
|
+
|
|
4
|
+
Removes components from an existing Aegis Stack project using manual file deletion.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from ..core.components import COMPONENTS, CORE_COMPONENTS, SchedulerBackend
|
|
12
|
+
from ..core.copier_manager import (
|
|
13
|
+
is_copier_project,
|
|
14
|
+
load_copier_answers,
|
|
15
|
+
)
|
|
16
|
+
from ..core.dependency_resolver import DependencyResolver
|
|
17
|
+
from ..core.manual_updater import ManualUpdater
|
|
18
|
+
from ..core.version_compatibility import validate_version_compatibility
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def remove_command(
|
|
22
|
+
components: str | None = typer.Argument(
|
|
23
|
+
None,
|
|
24
|
+
help="Comma-separated list of components to remove (scheduler,worker,database)",
|
|
25
|
+
),
|
|
26
|
+
interactive: bool = typer.Option(
|
|
27
|
+
False,
|
|
28
|
+
"--interactive",
|
|
29
|
+
"-i",
|
|
30
|
+
help="Use interactive component selection",
|
|
31
|
+
),
|
|
32
|
+
project_path: str = typer.Option(
|
|
33
|
+
".",
|
|
34
|
+
"--project-path",
|
|
35
|
+
"-p",
|
|
36
|
+
help="Path to the Aegis Stack project (default: current directory)",
|
|
37
|
+
),
|
|
38
|
+
yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt"),
|
|
39
|
+
force: bool = typer.Option(
|
|
40
|
+
False,
|
|
41
|
+
"--force",
|
|
42
|
+
"-f",
|
|
43
|
+
help="Force through version mismatch warnings",
|
|
44
|
+
),
|
|
45
|
+
) -> None:
|
|
46
|
+
"""
|
|
47
|
+
Remove components from an existing Aegis Stack project.
|
|
48
|
+
|
|
49
|
+
This command removes component files and updates project configuration.
|
|
50
|
+
WARNING: This operation deletes files and cannot be easily undone!
|
|
51
|
+
|
|
52
|
+
Examples:\\\\n
|
|
53
|
+
- aegis remove scheduler\\\\n
|
|
54
|
+
- aegis remove worker,database\\\\n
|
|
55
|
+
- aegis remove scheduler --project-path ../my-project\\\\n
|
|
56
|
+
|
|
57
|
+
Note: Core components (backend, frontend) cannot be removed.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
typer.echo("🛡️ Aegis Stack - Remove Components")
|
|
61
|
+
typer.echo("=" * 50)
|
|
62
|
+
|
|
63
|
+
# Resolve project path
|
|
64
|
+
target_path = Path(project_path).resolve()
|
|
65
|
+
|
|
66
|
+
# Validate it's a Copier project
|
|
67
|
+
if not is_copier_project(target_path):
|
|
68
|
+
typer.echo(
|
|
69
|
+
f"❌ Project at {target_path} was not generated with Copier.", err=True
|
|
70
|
+
)
|
|
71
|
+
typer.echo(
|
|
72
|
+
" The 'aegis remove' command only works with Copier-generated projects.",
|
|
73
|
+
err=True,
|
|
74
|
+
)
|
|
75
|
+
raise typer.Exit(1)
|
|
76
|
+
|
|
77
|
+
typer.echo(f"📁 Project: {target_path}")
|
|
78
|
+
|
|
79
|
+
# Check version compatibility between CLI and project template
|
|
80
|
+
validate_version_compatibility(target_path, command_name="remove", force=force)
|
|
81
|
+
|
|
82
|
+
# Validate components argument or interactive mode
|
|
83
|
+
if not interactive and not components:
|
|
84
|
+
typer.echo(
|
|
85
|
+
"❌ Error: components argument is required (or use --interactive)", err=True
|
|
86
|
+
)
|
|
87
|
+
typer.echo(" Usage: aegis remove scheduler,worker", err=True)
|
|
88
|
+
typer.echo(" Or: aegis remove --interactive", err=True)
|
|
89
|
+
raise typer.Exit(1)
|
|
90
|
+
|
|
91
|
+
# Interactive mode
|
|
92
|
+
if interactive:
|
|
93
|
+
if components:
|
|
94
|
+
typer.echo(
|
|
95
|
+
"⚠️ Warning: --interactive flag ignores component arguments",
|
|
96
|
+
err=False,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
from ..cli.interactive import interactive_component_remove_selection
|
|
100
|
+
|
|
101
|
+
selected_components = interactive_component_remove_selection(target_path)
|
|
102
|
+
|
|
103
|
+
if not selected_components:
|
|
104
|
+
typer.echo("\n✅ No components selected for removal")
|
|
105
|
+
raise typer.Exit(0)
|
|
106
|
+
|
|
107
|
+
# Convert to comma-separated string for existing logic
|
|
108
|
+
components = ",".join(selected_components)
|
|
109
|
+
|
|
110
|
+
# Auto-confirm in interactive mode (user already confirmed during selection)
|
|
111
|
+
yes = True
|
|
112
|
+
|
|
113
|
+
# Parse and validate components
|
|
114
|
+
assert components is not None # Already validated by check above
|
|
115
|
+
components_raw = [c.strip() for c in components.split(",")]
|
|
116
|
+
|
|
117
|
+
# Check for empty components
|
|
118
|
+
if any(not c for c in components_raw):
|
|
119
|
+
typer.echo("❌ Empty component name is not allowed", err=True)
|
|
120
|
+
raise typer.Exit(1)
|
|
121
|
+
|
|
122
|
+
selected_components = [c for c in components_raw if c]
|
|
123
|
+
|
|
124
|
+
# Validate components exist
|
|
125
|
+
try:
|
|
126
|
+
# Use the same validation logic as init command
|
|
127
|
+
errors = DependencyResolver.validate_components(selected_components)
|
|
128
|
+
if errors:
|
|
129
|
+
for error in errors:
|
|
130
|
+
typer.echo(f"❌ {error}", err=True)
|
|
131
|
+
raise typer.Exit(1)
|
|
132
|
+
|
|
133
|
+
except Exception as e:
|
|
134
|
+
typer.echo(f"❌ Component validation failed: {e}", err=True)
|
|
135
|
+
raise typer.Exit(1)
|
|
136
|
+
|
|
137
|
+
# Load existing project configuration
|
|
138
|
+
try:
|
|
139
|
+
existing_answers = load_copier_answers(target_path)
|
|
140
|
+
except Exception as e:
|
|
141
|
+
typer.echo(f"❌ Failed to load project configuration: {e}", err=True)
|
|
142
|
+
raise typer.Exit(1)
|
|
143
|
+
|
|
144
|
+
# Check which components are currently enabled
|
|
145
|
+
not_enabled = []
|
|
146
|
+
components_to_remove = []
|
|
147
|
+
|
|
148
|
+
for component in selected_components:
|
|
149
|
+
# Check if component is core (cannot be removed)
|
|
150
|
+
if component in CORE_COMPONENTS:
|
|
151
|
+
typer.echo(f"⚠️ Cannot remove core component: {component}", err=False)
|
|
152
|
+
continue
|
|
153
|
+
|
|
154
|
+
# Check if component is enabled
|
|
155
|
+
include_key = f"include_{component}"
|
|
156
|
+
if not existing_answers.get(include_key):
|
|
157
|
+
not_enabled.append(component)
|
|
158
|
+
else:
|
|
159
|
+
components_to_remove.append(component)
|
|
160
|
+
|
|
161
|
+
if not_enabled:
|
|
162
|
+
typer.echo(f"ℹ️ Not enabled: {', '.join(not_enabled)}", err=False)
|
|
163
|
+
|
|
164
|
+
if not components_to_remove:
|
|
165
|
+
typer.echo("✅ No components to remove!")
|
|
166
|
+
raise typer.Exit(0)
|
|
167
|
+
|
|
168
|
+
# Check for scheduler with sqlite backend - warn about persistence
|
|
169
|
+
if "scheduler" in components_to_remove:
|
|
170
|
+
scheduler_backend = existing_answers.get("scheduler_backend")
|
|
171
|
+
if scheduler_backend == SchedulerBackend.SQLITE.value:
|
|
172
|
+
typer.echo("\n⚠️ IMPORTANT: Scheduler Persistence Warning")
|
|
173
|
+
typer.echo(" Your scheduler uses SQLite for job persistence.")
|
|
174
|
+
typer.echo(" The database file at data/scheduler.db will remain.")
|
|
175
|
+
typer.echo()
|
|
176
|
+
typer.echo(" 💡 To keep your job history: Leave the database component")
|
|
177
|
+
typer.echo(" 💡 To remove all data: Also remove the database component")
|
|
178
|
+
typer.echo()
|
|
179
|
+
|
|
180
|
+
# Show what will be removed
|
|
181
|
+
typer.echo("\n⚠️ Components to remove:")
|
|
182
|
+
for component in components_to_remove:
|
|
183
|
+
if component in COMPONENTS:
|
|
184
|
+
desc = COMPONENTS[component].description
|
|
185
|
+
typer.echo(f" • {component}: {desc}")
|
|
186
|
+
|
|
187
|
+
# Confirm before proceeding
|
|
188
|
+
typer.echo()
|
|
189
|
+
typer.echo("⚠️ WARNING: This will DELETE component files from your project!")
|
|
190
|
+
typer.echo(" Make sure you have committed your changes to git.")
|
|
191
|
+
typer.echo()
|
|
192
|
+
|
|
193
|
+
if not yes and not typer.confirm("🗑️ Remove these components?"):
|
|
194
|
+
typer.echo("❌ Operation cancelled")
|
|
195
|
+
raise typer.Exit(0)
|
|
196
|
+
|
|
197
|
+
# Run manual removal for each component
|
|
198
|
+
typer.echo("\n🔄 Removing components...")
|
|
199
|
+
try:
|
|
200
|
+
updater = ManualUpdater(target_path)
|
|
201
|
+
|
|
202
|
+
# Remove each component sequentially
|
|
203
|
+
for component in components_to_remove:
|
|
204
|
+
typer.echo(f"\n📦 Removing {component}...")
|
|
205
|
+
|
|
206
|
+
# Remove the component
|
|
207
|
+
result = updater.remove_component(component)
|
|
208
|
+
|
|
209
|
+
if not result.success:
|
|
210
|
+
typer.echo(
|
|
211
|
+
f"❌ Failed to remove {component}: {result.error_message}", err=True
|
|
212
|
+
)
|
|
213
|
+
raise typer.Exit(1)
|
|
214
|
+
|
|
215
|
+
# Show results
|
|
216
|
+
if result.files_deleted:
|
|
217
|
+
typer.echo(f" ✅ Removed {len(result.files_deleted)} files")
|
|
218
|
+
|
|
219
|
+
typer.echo("\n✅ Components removed successfully!")
|
|
220
|
+
typer.echo("\n📝 Next steps:")
|
|
221
|
+
typer.echo(" 1. Run 'make check' to verify the changes")
|
|
222
|
+
typer.echo(" 2. Test your application")
|
|
223
|
+
typer.echo(" 3. Commit the changes to git")
|
|
224
|
+
|
|
225
|
+
except Exception as e:
|
|
226
|
+
typer.echo(f"\n❌ Failed to remove components: {e}", err=True)
|
|
227
|
+
raise typer.Exit(1)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Services command implementation.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from ..core.services import ServiceType, get_services_by_type
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def services_command() -> None:
|
|
11
|
+
"""List available services and their dependencies."""
|
|
12
|
+
|
|
13
|
+
typer.echo("\n🔧 AVAILABLE SERVICES")
|
|
14
|
+
typer.echo("=" * 40)
|
|
15
|
+
|
|
16
|
+
# Group services by type
|
|
17
|
+
service_types = [
|
|
18
|
+
(ServiceType.AUTH, "🔐 Authentication Services"),
|
|
19
|
+
(ServiceType.PAYMENT, "💰 Payment Services"),
|
|
20
|
+
(ServiceType.AI, "🤖 AI & Machine Learning Services"),
|
|
21
|
+
(ServiceType.NOTIFICATION, "📧 Notification Services"),
|
|
22
|
+
(ServiceType.ANALYTICS, "📊 Analytics Services"),
|
|
23
|
+
(ServiceType.STORAGE, "💾 Storage Services"),
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
services_found = False
|
|
27
|
+
for service_type, header in service_types:
|
|
28
|
+
type_services = get_services_by_type(service_type)
|
|
29
|
+
if type_services:
|
|
30
|
+
services_found = True
|
|
31
|
+
typer.echo(f"\n{header}")
|
|
32
|
+
typer.echo("-" * 40)
|
|
33
|
+
|
|
34
|
+
for name, spec in type_services.items():
|
|
35
|
+
typer.echo(f" {name:12} - {spec.description}")
|
|
36
|
+
if spec.required_components:
|
|
37
|
+
typer.echo(
|
|
38
|
+
f" Requires components: {', '.join(spec.required_components)}"
|
|
39
|
+
)
|
|
40
|
+
if spec.recommended_components:
|
|
41
|
+
typer.echo(
|
|
42
|
+
f" Recommends components: {', '.join(spec.recommended_components)}"
|
|
43
|
+
)
|
|
44
|
+
if spec.required_services:
|
|
45
|
+
typer.echo(
|
|
46
|
+
f" Requires services: {', '.join(spec.required_services)}"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
if not services_found:
|
|
50
|
+
typer.echo(" No services available yet.")
|
|
51
|
+
|
|
52
|
+
typer.echo("\n💡 Use 'aegis init PROJECT_NAME --services auth' to add services")
|