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.
Files changed (392) hide show
  1. aegis/__init__.py +5 -0
  2. aegis/__main__.py +51 -0
  3. aegis/cli/__init__.py +6 -0
  4. aegis/cli/callbacks.py +114 -0
  5. aegis/cli/interactive.py +611 -0
  6. aegis/cli/utils.py +70 -0
  7. aegis/cli/validators.py +34 -0
  8. aegis/commands/__init__.py +6 -0
  9. aegis/commands/add.py +353 -0
  10. aegis/commands/add_service.py +332 -0
  11. aegis/commands/components.py +35 -0
  12. aegis/commands/init.py +370 -0
  13. aegis/commands/remove.py +227 -0
  14. aegis/commands/services.py +52 -0
  15. aegis/commands/update.py +252 -0
  16. aegis/commands/version.py +12 -0
  17. aegis/config/__init__.py +1 -0
  18. aegis/config/shared_files.py +136 -0
  19. aegis/core/CLAUDE.md +377 -0
  20. aegis/core/__init__.py +6 -0
  21. aegis/core/component_files.py +228 -0
  22. aegis/core/component_utils.py +220 -0
  23. aegis/core/components.py +127 -0
  24. aegis/core/copier_manager.py +315 -0
  25. aegis/core/copier_updater.py +475 -0
  26. aegis/core/dependency_resolver.py +119 -0
  27. aegis/core/manual_updater.py +554 -0
  28. aegis/core/post_gen_tasks.py +547 -0
  29. aegis/core/service_resolver.py +261 -0
  30. aegis/core/services.py +157 -0
  31. aegis/core/template_generator.py +266 -0
  32. aegis/core/version_compatibility.py +259 -0
  33. aegis/templates/CLAUDE.md +591 -0
  34. aegis/templates/cookiecutter-aegis-project/cookiecutter.json +39 -0
  35. aegis/templates/cookiecutter-aegis-project/hooks/post_gen_project.py +214 -0
  36. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.dockerignore +71 -0
  37. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.env.example.j2 +130 -0
  38. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.gitignore +131 -0
  39. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/Dockerfile +53 -0
  40. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/Makefile +236 -0
  41. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/README.md.j2 +196 -0
  42. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/alembic.ini.j2 +111 -0
  43. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/env.py.j2 +91 -0
  44. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/script.py.mako +25 -0
  45. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/versions/001_initial_auth.py.j2 +51 -0
  46. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/__init__.py +5 -0
  47. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/__init__.py +6 -0
  48. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/ai.py.j2 +700 -0
  49. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/ai_rendering.py +361 -0
  50. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/auth.py.j2 +253 -0
  51. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/health.py.j2 +419 -0
  52. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/load_test.py.j2 +656 -0
  53. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/main.py.j2 +65 -0
  54. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/marko_terminal_renderer.py +489 -0
  55. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/tasks.py.j2 +328 -0
  56. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/{% if cookiecutter.include_scheduler == /"yes/" %}tasks.py{% endif %}" +340 -0
  57. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/__init__.py +0 -0
  58. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/__init__.py +0 -0
  59. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/ai/__init__.py +8 -0
  60. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/ai/router.py +329 -0
  61. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/auth/__init__.py +1 -0
  62. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/auth/router.py +64 -0
  63. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/deps.py +58 -0
  64. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/health.py +163 -0
  65. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/models.py.j2 +280 -0
  66. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/routing.py.j2 +32 -0
  67. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/scheduler.py.j2 +121 -0
  68. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/worker.py.j2 +478 -0
  69. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/hooks.py +144 -0
  70. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/main.py +31 -0
  71. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/middleware/__init__.py +1 -0
  72. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/middleware/cors.py +20 -0
  73. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/shutdown/__init__.py +1 -0
  74. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/shutdown/cleanup.py +14 -0
  75. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/startup/__init__.py +1 -0
  76. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/startup/component_health.py.j2 +418 -0
  77. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/startup/database_init.py.j2 +83 -0
  78. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/__init__.py +5 -0
  79. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/controls/__init__.py +27 -0
  80. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/controls/table.py +78 -0
  81. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/controls/text.py +142 -0
  82. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/__init__.py.j2 +47 -0
  83. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/ai_card.py +287 -0
  84. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/auth_card.py +198 -0
  85. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/base_card.py +256 -0
  86. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/card_factory.py +227 -0
  87. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/card_utils.py +333 -0
  88. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/database_card.py +420 -0
  89. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/fastapi_card.py +328 -0
  90. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/flet_card.py +267 -0
  91. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/redis_card.py +322 -0
  92. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/scheduler_card.py +352 -0
  93. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/services_card.py +233 -0
  94. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/worker_card.py +684 -0
  95. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/main.py.j2 +653 -0
  96. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/theme.py +48 -0
  97. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/scheduler/__init__.py +1 -0
  98. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/scheduler/main.py.j2 +156 -0
  99. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/CLAUDE.md.j2 +213 -0
  100. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/__init__.py +6 -0
  101. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/constants.py.j2 +30 -0
  102. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/pools.py +97 -0
  103. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/__init__.py +1 -0
  104. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/load_test.py +55 -0
  105. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/media.py +49 -0
  106. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/system.py +44 -0
  107. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/registry.py +139 -0
  108. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/__init__.py +120 -0
  109. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/load_tasks.py +507 -0
  110. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/simple_system_tasks.py +33 -0
  111. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/system_tasks.py +281 -0
  112. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/config.py.j2 +178 -0
  113. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/constants.py +58 -0
  114. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/db.py.j2 +176 -0
  115. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/log.py +92 -0
  116. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/security.py +62 -0
  117. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/entrypoints/__init__.py +1 -0
  118. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/entrypoints/webserver.py +40 -0
  119. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/entrypoints/{% if cookiecutter.include_scheduler == /"yes/" %}scheduler.py{% endif %}" +21 -0
  120. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/integrations/__init__.py +0 -0
  121. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/integrations/main.py +62 -0
  122. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/models/__init__.py +1 -0
  123. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/models/user.py +44 -0
  124. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/py.typed +0 -0
  125. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/__init__.py +1 -0
  126. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/__init__.py +8 -0
  127. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/config.py +130 -0
  128. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/conversation.py +213 -0
  129. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/health.py +96 -0
  130. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/models.py +229 -0
  131. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/providers.py +370 -0
  132. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/service.py +388 -0
  133. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/__init__.py +1 -0
  134. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/auth_service.py +41 -0
  135. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/health.py +164 -0
  136. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/user_service.py +83 -0
  137. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/backend/middleware_inspector.py.j2 +223 -0
  138. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/backend/models.py.j2 +70 -0
  139. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/backend/route_inspector.py.j2 +155 -0
  140. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/load_test.py +679 -0
  141. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/load_test_models.py +266 -0
  142. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/__init__.py.j2 +21 -0
  143. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/models.py.j2 +119 -0
  144. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/scheduled_task_manager.py.j2 +273 -0
  145. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/task_monitor.py.j2 +189 -0
  146. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/shared/__init__.py +15 -0
  147. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/shared/models.py +26 -0
  148. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/__init__.py +52 -0
  149. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/alerts.py +94 -0
  150. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/backup.py.j2 +119 -0
  151. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/health.py.j2 +1333 -0
  152. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/models.py +243 -0
  153. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/ui.py +52 -0
  154. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/assets/aegis-manifesto-dark.png +0 -0
  155. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/assets/aegis-manifesto-square-backup.png +0 -0
  156. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/assets/aegis-manifesto.png +0 -0
  157. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/.dockerignore +71 -0
  158. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/.env.example.j2 +64 -0
  159. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/.gitignore +131 -0
  160. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/Dockerfile +53 -0
  161. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/Makefile +211 -0
  162. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/README.md.j2 +172 -0
  163. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/docker-compose.yml.j2 +78 -0
  164. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/mkdocs.yml.j2 +62 -0
  165. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/pyproject.toml.j2 +120 -0
  166. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/uv.lock +1673 -0
  167. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docker-compose.yml.j2 +200 -0
  168. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/api.md +191 -0
  169. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/components/scheduler.md +0 -0
  170. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/components/scheduler.md.j2 +621 -0
  171. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/development.md +215 -0
  172. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/health.md +240 -0
  173. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/javascripts/mermaid-config.js +62 -0
  174. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/stylesheets/mermaid.css +95 -0
  175. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/mkdocs.yml.j2 +62 -0
  176. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/pyproject.toml.j2 +131 -0
  177. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/entrypoint.sh +87 -0
  178. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/entrypoint.sh.j2 +93 -0
  179. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/gen_docs.py +16 -0
  180. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/__init__.py +1 -0
  181. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_auth_endpoints.py.j2 +307 -0
  182. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_health_endpoints.py.j2 +262 -0
  183. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_scheduler_endpoints.py.j2 +214 -0
  184. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_worker_endpoints.py.j2 +165 -0
  185. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/cli/test_ai_rendering.py +427 -0
  186. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/cli/test_conversation_memory.py +465 -0
  187. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/components/test_scheduler.py +43 -0
  188. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/conftest.py.j2 +195 -0
  189. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/__init__.py +1 -0
  190. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/__init__.py +1 -0
  191. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/conftest.py +78 -0
  192. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/test_health.py +157 -0
  193. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/test_models.py +164 -0
  194. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/test_service.py +198 -0
  195. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_auth_integration.py.j2 +528 -0
  196. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_component_integration.py.j2 +387 -0
  197. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_conversation_persistence.py +342 -0
  198. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_health_logic.py.j2 +663 -0
  199. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_load_test_models.py +619 -0
  200. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_load_test_service.py +603 -0
  201. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_middleware_inspector.py.j2 +248 -0
  202. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_scheduled_task_manager.py.j2 +292 -0
  203. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_system_service.py +98 -0
  204. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_worker_health_registration.py.j2 +257 -0
  205. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/test_core.py +49 -0
  206. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/uv.lock +1673 -0
  207. aegis/templates/copier-aegis-project/{{ project_slug }}/.copier-answers.yml.jinja +21 -0
  208. aegis/templates/copier-aegis-project/{{ project_slug }}/.dockerignore +71 -0
  209. aegis/templates/copier-aegis-project/{{ project_slug }}/.env.example.jinja +130 -0
  210. aegis/templates/copier-aegis-project/{{ project_slug }}/.gitignore +131 -0
  211. aegis/templates/copier-aegis-project/{{ project_slug }}/Dockerfile +53 -0
  212. aegis/templates/copier-aegis-project/{{ project_slug }}/Makefile.jinja +236 -0
  213. aegis/templates/copier-aegis-project/{{ project_slug }}/README.md.jinja +196 -0
  214. aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/alembic.ini.jinja +111 -0
  215. aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/env.py.jinja +91 -0
  216. aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/script.py.mako +25 -0
  217. aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/versions/001_initial_auth.py.jinja +51 -0
  218. aegis/templates/copier-aegis-project/{{ project_slug }}/app/__init__.py.jinja +5 -0
  219. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/__init__.py.jinja +6 -0
  220. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/ai.py.jinja +700 -0
  221. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/ai_rendering.py +360 -0
  222. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/auth.py.jinja +253 -0
  223. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/health.py.jinja +419 -0
  224. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/load_test.py.jinja +656 -0
  225. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/main.py.jinja +65 -0
  226. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/marko_terminal_renderer.py +489 -0
  227. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/tasks.py.jinja +328 -0
  228. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/__init__.py +0 -0
  229. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/__init__.py +0 -0
  230. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/ai/__init__.py +8 -0
  231. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/ai/router.py +329 -0
  232. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/auth/__init__.py +1 -0
  233. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/auth/router.py +64 -0
  234. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/deps.py +58 -0
  235. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/health.py.jinja +163 -0
  236. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/models.py.jinja +280 -0
  237. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/routing.py.jinja +32 -0
  238. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/scheduler.py.jinja +121 -0
  239. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/worker.py.jinja +478 -0
  240. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/hooks.py +144 -0
  241. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/main.py +31 -0
  242. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/middleware/__init__.py +1 -0
  243. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/middleware/cors.py +20 -0
  244. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/shutdown/__init__.py +1 -0
  245. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/shutdown/cleanup.py +14 -0
  246. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/startup/__init__.py +1 -0
  247. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/startup/component_health.py.jinja +418 -0
  248. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/startup/database_init.py.jinja +83 -0
  249. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/__init__.py +5 -0
  250. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/__init__.py +27 -0
  251. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/table.py +78 -0
  252. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/text.py +142 -0
  253. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/__init__.py.jinja +47 -0
  254. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/ai_card.py +287 -0
  255. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/auth_card.py +198 -0
  256. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/base_card.py +256 -0
  257. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/card_factory.py +227 -0
  258. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/card_utils.py +333 -0
  259. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/database_card.py +420 -0
  260. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/fastapi_card.py +328 -0
  261. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/flet_card.py +267 -0
  262. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/redis_card.py +322 -0
  263. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/scheduler_card.py +352 -0
  264. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/services_card.py +233 -0
  265. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/worker_card.py +684 -0
  266. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/main.py.jinja +653 -0
  267. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/theme.py +48 -0
  268. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/scheduler/__init__.py +1 -0
  269. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/scheduler/main.py.jinja +156 -0
  270. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/CLAUDE.md.jinja +213 -0
  271. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/__init__.py +6 -0
  272. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/constants.py.jinja +30 -0
  273. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/pools.py +97 -0
  274. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/__init__.py +1 -0
  275. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/load_test.py +55 -0
  276. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/media.py +49 -0
  277. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/system.py +44 -0
  278. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/registry.py +139 -0
  279. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/__init__.py +120 -0
  280. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/load_tasks.py +507 -0
  281. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/simple_system_tasks.py +33 -0
  282. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/system_tasks.py +281 -0
  283. aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/config.py.jinja +178 -0
  284. aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/constants.py +58 -0
  285. aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/db.py.jinja +176 -0
  286. aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/log.py +92 -0
  287. aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/security.py +62 -0
  288. aegis/templates/copier-aegis-project/{{ project_slug }}/app/entrypoints/__init__.py +1 -0
  289. aegis/templates/copier-aegis-project/{{ project_slug }}/app/entrypoints/scheduler.py.jinja +21 -0
  290. aegis/templates/copier-aegis-project/{{ project_slug }}/app/entrypoints/webserver.py +39 -0
  291. aegis/templates/copier-aegis-project/{{ project_slug }}/app/integrations/__init__.py +0 -0
  292. aegis/templates/copier-aegis-project/{{ project_slug }}/app/integrations/main.py +61 -0
  293. aegis/templates/copier-aegis-project/{{ project_slug }}/app/models/__init__.py +1 -0
  294. aegis/templates/copier-aegis-project/{{ project_slug }}/app/models/user.py +44 -0
  295. aegis/templates/copier-aegis-project/{{ project_slug }}/app/py.typed +0 -0
  296. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/__init__.py +1 -0
  297. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/__init__.py +8 -0
  298. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/config.py +130 -0
  299. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/conversation.py +213 -0
  300. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/health.py +96 -0
  301. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/models.py +229 -0
  302. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/providers.py.jinja +370 -0
  303. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/service.py +387 -0
  304. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/__init__.py +1 -0
  305. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/auth_service.py +40 -0
  306. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/health.py +162 -0
  307. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/user_service.py +82 -0
  308. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/backend/middleware_inspector.py.jinja +223 -0
  309. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/backend/models.py.jinja +70 -0
  310. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/backend/route_inspector.py.jinja +155 -0
  311. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/load_test.py +678 -0
  312. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/load_test_models.py +265 -0
  313. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/__init__.py.jinja +21 -0
  314. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/models.py.jinja +119 -0
  315. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/scheduled_task_manager.py.jinja +273 -0
  316. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/task_monitor.py.jinja +189 -0
  317. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/shared/__init__.py +15 -0
  318. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/shared/models.py +26 -0
  319. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/__init__.py +52 -0
  320. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/alerts.py +94 -0
  321. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/backup.py.jinja +119 -0
  322. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/health.py.jinja +1333 -0
  323. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/models.py +243 -0
  324. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/ui.py +52 -0
  325. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57223!aegis-manifesto.png +0 -0
  326. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57224!aegis-manifesto-dark.png +0 -0
  327. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57225!aegis-manifesto-square-backup.png +0 -0
  328. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57533!aegis-manifesto.png +0 -0
  329. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57534!aegis-manifesto-dark.png +0 -0
  330. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57538!aegis-manifesto-square-backup.png +0 -0
  331. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57897!aegis-manifesto.png +0 -0
  332. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57898!aegis-manifesto-dark.png +0 -0
  333. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57904!aegis-manifesto-square-backup.png +0 -0
  334. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58315!aegis-manifesto.png +0 -0
  335. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58316!aegis-manifesto-dark.png +0 -0
  336. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58324!aegis-manifesto-square-backup.png +0 -0
  337. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58837!aegis-manifesto.png +0 -0
  338. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58838!aegis-manifesto-dark.png +0 -0
  339. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58849!aegis-manifesto-square-backup.png +0 -0
  340. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/aegis-manifesto-dark.png +0 -0
  341. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/aegis-manifesto-square-backup.png +0 -0
  342. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/aegis-manifesto.png +0 -0
  343. aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/.env.example.jinja +64 -0
  344. aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/README.md.jinja +172 -0
  345. aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/docker-compose.yml.jinja +78 -0
  346. aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/mkdocs.yml.jinja +62 -0
  347. aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/pyproject.toml.jinja +120 -0
  348. aegis/templates/copier-aegis-project/{{ project_slug }}/docker-compose.yml.jinja +200 -0
  349. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/api.md.jinja +191 -0
  350. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/components/scheduler.md +0 -0
  351. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/components/scheduler.md.jinja +621 -0
  352. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/development.md.jinja +215 -0
  353. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/health.md.jinja +240 -0
  354. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/javascripts/mermaid-config.js +62 -0
  355. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/stylesheets/mermaid.css +95 -0
  356. aegis/templates/copier-aegis-project/{{ project_slug }}/mkdocs.yml.jinja +62 -0
  357. aegis/templates/copier-aegis-project/{{ project_slug }}/pyproject.toml.jinja +131 -0
  358. aegis/templates/copier-aegis-project/{{ project_slug }}/scripts/entrypoint.sh +87 -0
  359. aegis/templates/copier-aegis-project/{{ project_slug }}/scripts/entrypoint.sh.jinja +93 -0
  360. aegis/templates/copier-aegis-project/{{ project_slug }}/scripts/gen_docs.py +16 -0
  361. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/__init__.py +1 -0
  362. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_auth_endpoints.py.jinja +307 -0
  363. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_health_endpoints.py.jinja +262 -0
  364. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_scheduler_endpoints.py.jinja +214 -0
  365. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_worker_endpoints.py.jinja +165 -0
  366. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/cli/test_ai_rendering.py +427 -0
  367. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/cli/test_conversation_memory.py +465 -0
  368. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/components/test_scheduler.py +43 -0
  369. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/conftest.py.jinja +195 -0
  370. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/__init__.py +1 -0
  371. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/__init__.py +1 -0
  372. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/conftest.py +78 -0
  373. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/test_health.py +157 -0
  374. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/test_models.py +164 -0
  375. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/test_service.py +198 -0
  376. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_auth_integration.py.jinja +528 -0
  377. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_component_integration.py.jinja +387 -0
  378. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_conversation_persistence.py +342 -0
  379. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_health_logic.py.jinja +663 -0
  380. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_load_test_models.py +619 -0
  381. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_load_test_service.py +603 -0
  382. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_middleware_inspector.py.jinja +248 -0
  383. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_scheduled_task_manager.py.jinja +292 -0
  384. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_system_service.py +98 -0
  385. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_worker_health_registration.py.jinja +257 -0
  386. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/test_core.py +49 -0
  387. aegis/templates/copier-aegis-project/{{ project_slug }}/uv.lock +1673 -0
  388. aegis_stack-0.2.0rc2.dist-info/METADATA +165 -0
  389. aegis_stack-0.2.0rc2.dist-info/RECORD +392 -0
  390. aegis_stack-0.2.0rc2.dist-info/WHEEL +4 -0
  391. aegis_stack-0.2.0rc2.dist-info/entry_points.txt +3 -0
  392. 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)
@@ -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")