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
@@ -0,0 +1,547 @@
1
+ """
2
+ Shared post-generation tasks for Cookiecutter and Copier.
3
+
4
+ This module provides common post-generation functionality used by both
5
+ template engines to avoid code duplication and ensure consistent behavior.
6
+ """
7
+
8
+ import os
9
+ import shutil
10
+ import subprocess
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ # Task configuration constants (following tests/cli/test_utils.py pattern)
15
+ POST_GEN_TIMEOUT_INSTALL = 300 # 5 minutes for dependency installation
16
+ POST_GEN_TIMEOUT_FORMAT = 60 # 1 minute for code formatting
17
+ POST_GEN_TIMEOUT_MIGRATION = 30 # 30 seconds for database migration
18
+
19
+
20
+ def get_component_file_mapping() -> dict[str, list[str]]:
21
+ """
22
+ Get mapping of components to their files.
23
+
24
+ Returns a dictionary mapping component names to lists of files/directories
25
+ that belong to that component. This is used by both cleanup_components()
26
+ and component_files.py for consistency.
27
+
28
+ Returns:
29
+ Dict mapping component names to file paths (relative to project root)
30
+ """
31
+ return {
32
+ "scheduler": [
33
+ "app/entrypoints/scheduler.py",
34
+ "app/components/scheduler",
35
+ "tests/components/test_scheduler.py",
36
+ "docs/components/scheduler.md",
37
+ "app/components/backend/api/scheduler.py",
38
+ "tests/api/test_scheduler_endpoints.py",
39
+ "app/components/frontend/dashboard/cards/scheduler_card.py",
40
+ "tests/services/test_scheduled_task_manager.py",
41
+ ],
42
+ "scheduler_persistence": [ # Only for sqlite backend
43
+ "app/services/scheduler",
44
+ "app/cli/tasks.py",
45
+ "app/components/backend/api/scheduler.py",
46
+ "tests/api/test_scheduler_endpoints.py",
47
+ "tests/services/test_scheduled_task_manager.py",
48
+ ],
49
+ "worker": [
50
+ "app/components/worker",
51
+ "app/cli/load_test.py",
52
+ "app/services/load_test.py",
53
+ "app/services/load_test_models.py",
54
+ "tests/services/test_load_test_models.py",
55
+ "tests/services/test_load_test_service.py",
56
+ "tests/services/test_worker_health_registration.py",
57
+ "app/components/backend/api/worker.py",
58
+ "tests/api/test_worker_endpoints.py",
59
+ "app/components/frontend/dashboard/cards/worker_card.py",
60
+ ],
61
+ "database": [
62
+ "app/core/db.py",
63
+ ],
64
+ "auth": [
65
+ "app/components/backend/api/auth",
66
+ "app/models/user.py",
67
+ "app/services/auth",
68
+ "app/core/security.py",
69
+ "app/cli/auth.py",
70
+ "tests/api/test_auth_endpoints.py",
71
+ "tests/services/test_auth_service.py",
72
+ "tests/services/test_auth_integration.py",
73
+ "tests/models/test_user.py",
74
+ "alembic",
75
+ ],
76
+ "ai": [
77
+ "app/components/backend/api/ai",
78
+ "app/services/ai",
79
+ "app/cli/ai.py",
80
+ "app/cli/ai_rendering.py",
81
+ "app/cli/marko_terminal_renderer.py",
82
+ "tests/api/test_ai_endpoints.py",
83
+ "tests/services/test_conversation_persistence.py",
84
+ "tests/cli/test_ai_rendering.py",
85
+ "tests/cli/test_conversation_memory.py",
86
+ "tests/services/ai",
87
+ ],
88
+ }
89
+
90
+
91
+ def remove_file(project_path: Path, filepath: str) -> None:
92
+ """
93
+ Remove a file from the generated project.
94
+
95
+ Args:
96
+ project_path: Path to the project directory
97
+ filepath: Relative path to the file to remove
98
+ """
99
+ full_path = project_path / filepath
100
+ if full_path.exists():
101
+ full_path.unlink()
102
+
103
+
104
+ def remove_dir(project_path: Path, dirpath: str) -> None:
105
+ """
106
+ Remove a directory from the generated project.
107
+
108
+ Args:
109
+ project_path: Path to the project directory
110
+ dirpath: Relative path to the directory to remove
111
+ """
112
+ full_path = project_path / dirpath
113
+ if full_path.exists():
114
+ shutil.rmtree(full_path)
115
+
116
+
117
+ def cleanup_components(project_path: Path, context: dict[str, Any]) -> None:
118
+ """
119
+ Remove component files based on component selection.
120
+
121
+ This function handles component cleanup for both Cookiecutter and Copier
122
+ template engines, ensuring identical behavior.
123
+
124
+ Args:
125
+ project_path: Path to the generated project
126
+ context: Dictionary with component/service flags
127
+
128
+ Note:
129
+ Handles both Cookiecutter (string "yes"/"no") and Copier (boolean true/false)
130
+ context values for maximum compatibility.
131
+ """
132
+
133
+ # Helper to handle both bool and string values from different template engines
134
+ def is_enabled(key: str) -> bool:
135
+ value = context.get(key)
136
+ return value is True or value == "yes"
137
+
138
+ # Remove scheduler component if not selected
139
+ if not is_enabled("include_scheduler"):
140
+ remove_file(project_path, "app/entrypoints/scheduler.py")
141
+ remove_dir(project_path, "app/components/scheduler")
142
+ remove_file(project_path, "tests/components/test_scheduler.py")
143
+ remove_file(project_path, "docs/components/scheduler.md")
144
+ remove_file(project_path, "app/components/backend/api/scheduler.py")
145
+ remove_file(project_path, "tests/api/test_scheduler_endpoints.py")
146
+ remove_file(
147
+ project_path, "app/components/frontend/dashboard/cards/scheduler_card.py"
148
+ )
149
+ remove_file(project_path, "tests/services/test_scheduled_task_manager.py")
150
+
151
+ # Remove scheduler service if using memory backend
152
+ # The service is only useful when we can persist to a database
153
+ scheduler_backend = context.get("scheduler_backend", "memory")
154
+ if scheduler_backend == "memory":
155
+ remove_dir(project_path, "app/services/scheduler")
156
+ remove_file(project_path, "app/cli/tasks.py")
157
+ remove_file(project_path, "app/components/backend/api/scheduler.py")
158
+ remove_file(project_path, "tests/api/test_scheduler_endpoints.py")
159
+ remove_file(project_path, "tests/services/test_scheduled_task_manager.py")
160
+
161
+ # Remove worker component if not selected
162
+ if not is_enabled("include_worker"):
163
+ remove_dir(project_path, "app/components/worker")
164
+ remove_file(project_path, "app/cli/load_test.py")
165
+ remove_file(project_path, "app/services/load_test.py")
166
+ remove_file(project_path, "app/services/load_test_models.py")
167
+ remove_file(project_path, "tests/services/test_load_test_models.py")
168
+ remove_file(project_path, "tests/services/test_load_test_service.py")
169
+ remove_file(project_path, "tests/services/test_worker_health_registration.py")
170
+ remove_file(project_path, "app/components/backend/api/worker.py")
171
+ remove_file(project_path, "tests/api/test_worker_endpoints.py")
172
+ remove_file(
173
+ project_path, "app/components/frontend/dashboard/cards/worker_card.py"
174
+ )
175
+
176
+ # Remove shared component integration tests only when BOTH scheduler AND worker disabled
177
+ if not is_enabled("include_scheduler") and not is_enabled("include_worker"):
178
+ remove_file(project_path, "tests/services/test_component_integration.py")
179
+ remove_file(project_path, "tests/services/test_health_logic.py")
180
+
181
+ # Remove database component if not selected
182
+ if not is_enabled("include_database"):
183
+ remove_file(project_path, "app/core/db.py")
184
+
185
+ # Remove cache component if not selected
186
+ if not is_enabled("include_cache"):
187
+ pass # Placeholder - cache component doesn't exist yet
188
+
189
+ # Remove auth service if not selected
190
+ if not is_enabled("include_auth"):
191
+ remove_dir(project_path, "app/components/backend/api/auth")
192
+ remove_file(project_path, "app/models/user.py")
193
+ remove_dir(project_path, "app/services/auth")
194
+ remove_file(project_path, "app/core/security.py")
195
+ remove_file(project_path, "app/cli/auth.py")
196
+ remove_file(project_path, "tests/api/test_auth_endpoints.py")
197
+ remove_file(project_path, "tests/services/test_auth_service.py")
198
+ remove_file(project_path, "tests/services/test_auth_integration.py")
199
+ remove_file(project_path, "tests/models/test_user.py")
200
+ remove_dir(project_path, "alembic")
201
+
202
+ # Remove AI service if not selected
203
+ if not is_enabled("include_ai"):
204
+ remove_dir(project_path, "app/components/backend/api/ai")
205
+ remove_dir(project_path, "app/services/ai")
206
+ remove_file(project_path, "app/cli/ai.py")
207
+ remove_file(project_path, "app/cli/ai_rendering.py")
208
+ remove_file(project_path, "app/cli/marko_terminal_renderer.py")
209
+ remove_file(project_path, "tests/api/test_ai_endpoints.py")
210
+ remove_file(project_path, "tests/services/test_conversation_persistence.py")
211
+ remove_file(project_path, "tests/cli/test_ai_rendering.py")
212
+ remove_file(project_path, "tests/cli/test_conversation_memory.py")
213
+ remove_dir(project_path, "tests/services/ai")
214
+
215
+ # Clean up empty docs/components directory if no components selected
216
+ if (
217
+ not is_enabled("include_scheduler")
218
+ and not is_enabled("include_worker")
219
+ and not is_enabled("include_database")
220
+ and not is_enabled("include_cache")
221
+ ):
222
+ remove_dir(project_path, "docs/components")
223
+
224
+
225
+ def copy_service_files(
226
+ project_path: Path, service_name: str, template_path: Path
227
+ ) -> None:
228
+ """
229
+ Copy service-specific files from template to project.
230
+
231
+ This is needed when services are added post-generation via Copier update.
232
+ Copier can only re-render existing files - it cannot copy new directories
233
+ that were excluded during initial generation.
234
+
235
+ Args:
236
+ project_path: Path to the project directory
237
+ service_name: Name of the service ('auth', 'ai', etc.)
238
+ template_path: Path to the Copier template directory
239
+
240
+ Note:
241
+ Uses get_component_file_mapping() to know which files belong to each service.
242
+ """
243
+ # Get the file mapping for this service
244
+ file_mapping = get_component_file_mapping()
245
+ if service_name not in file_mapping:
246
+ print(f"āš ļø Unknown service '{service_name}' - skipping file copy")
247
+ return
248
+
249
+ service_files = file_mapping[service_name]
250
+ print(f"šŸ“ Copying {service_name} service files from template...")
251
+
252
+ # The template is at: aegis-stack/aegis/templates/copier-aegis-project/{{ project_slug }}/
253
+ # We need to find the template content directory
254
+ template_content = template_path / "{{ project_slug }}"
255
+ if not template_content.exists():
256
+ print(f"āš ļø Template content directory not found: {template_content}")
257
+ return
258
+
259
+ copied_count = 0
260
+ for rel_path in service_files:
261
+ src = template_content / rel_path
262
+ dst = project_path / rel_path
263
+
264
+ # Skip if source doesn't exist (might be conditional on other settings)
265
+ if not src.exists():
266
+ continue
267
+
268
+ # Create parent directory if needed
269
+ dst.parent.mkdir(parents=True, exist_ok=True)
270
+
271
+ # Copy file or directory
272
+ if src.is_dir():
273
+ if dst.exists():
274
+ # Skip if already exists (don't overwrite existing customizations)
275
+ continue
276
+ shutil.copytree(src, dst)
277
+ copied_count += 1
278
+ else:
279
+ # For files, check if .jinja extension (template file)
280
+ if src.suffix == ".jinja":
281
+ # This is a Jinja2 template - we need to render it
282
+ # For now, skip template files (they'll be handled by Copier update)
283
+ continue
284
+ # Copy regular file
285
+ shutil.copy2(src, dst)
286
+ copied_count += 1
287
+
288
+ if copied_count > 0:
289
+ print(f"āœ… Copied {copied_count} {service_name} service files")
290
+ else:
291
+ print(f"āš ļø No {service_name} files copied (may already exist or be templates)")
292
+
293
+
294
+ def install_dependencies(project_path: Path) -> bool:
295
+ """
296
+ Install project dependencies using uv.
297
+
298
+ Args:
299
+ project_path: Path to the project directory
300
+
301
+ Returns:
302
+ True if installation succeeded, False otherwise
303
+ """
304
+ try:
305
+ print("šŸ“¦ Installing dependencies with uv...")
306
+
307
+ # Unset VIRTUAL_ENV to avoid conflicts with parent project's venv
308
+ env = os.environ.copy()
309
+ env.pop("VIRTUAL_ENV", None)
310
+
311
+ result = subprocess.run(
312
+ ["uv", "sync"],
313
+ cwd=project_path,
314
+ capture_output=True,
315
+ text=True,
316
+ timeout=POST_GEN_TIMEOUT_INSTALL,
317
+ env=env,
318
+ )
319
+
320
+ if result.returncode == 0:
321
+ print("āœ… Dependencies installed successfully")
322
+ return True
323
+ else:
324
+ print("āš ļø Dependency installation failed")
325
+ if result.stderr:
326
+ print(f" Error: {result.stderr.strip()}")
327
+ print("šŸ’” Run 'uv sync' manually after project creation")
328
+ return False
329
+
330
+ except subprocess.TimeoutExpired:
331
+ print("āš ļø Dependency installation timeout - run 'uv sync' manually")
332
+ return False
333
+ except FileNotFoundError:
334
+ print("āš ļø uv not found in PATH")
335
+ print("šŸ’” Install uv first: https://github.com/astral-sh/uv")
336
+ return False
337
+ except Exception as e:
338
+ print(f"āš ļø Dependency installation failed: {e}")
339
+ print("šŸ’” Run 'uv sync' manually after project creation")
340
+ return False
341
+
342
+
343
+ def setup_env_file(project_path: Path) -> bool:
344
+ """
345
+ Copy .env.example to .env if .env doesn't exist.
346
+
347
+ Args:
348
+ project_path: Path to the project directory
349
+
350
+ Returns:
351
+ True if setup succeeded or .env already exists, False on error
352
+ """
353
+ try:
354
+ print("šŸ“„ Setting up environment configuration...")
355
+ env_example = project_path / ".env.example"
356
+ env_file = project_path / ".env"
357
+
358
+ if env_example.exists() and not env_file.exists():
359
+ shutil.copy(env_example, env_file)
360
+ print("āœ… Environment file created from .env.example")
361
+ return True
362
+ elif env_file.exists():
363
+ print("āœ… Environment file already exists")
364
+ return True
365
+ else:
366
+ print("āš ļø No .env.example file found")
367
+ return False
368
+
369
+ except Exception as e:
370
+ print(f"āš ļø Environment setup failed: {e}")
371
+ print("šŸ’” Copy .env.example to .env manually")
372
+ return False
373
+
374
+
375
+ def run_migrations(project_path: Path, include_auth: bool = False) -> bool:
376
+ """
377
+ Run Alembic database migrations if auth service is enabled.
378
+
379
+ Args:
380
+ project_path: Path to the project directory
381
+ include_auth: Whether auth service is enabled
382
+
383
+ Returns:
384
+ True if migrations succeeded or not needed, False on error
385
+ """
386
+ if not include_auth:
387
+ return True # No migrations needed
388
+
389
+ try:
390
+ print("šŸ—ƒļø Setting up database with auth schema...")
391
+
392
+ # Ensure data directory exists
393
+ data_dir = project_path / "data"
394
+ data_dir.mkdir(exist_ok=True)
395
+
396
+ # Verify alembic config exists before running migration
397
+ alembic_ini_path = project_path / "alembic" / "alembic.ini"
398
+ if not alembic_ini_path.exists():
399
+ print(f"āš ļø Alembic config file not found at {alembic_ini_path}")
400
+ print(
401
+ "šŸ’” Skipping database migration. Please ensure the config file exists "
402
+ "and run 'alembic upgrade head' manually."
403
+ )
404
+ return False
405
+
406
+ # Run alembic migrations using uv run (ensures correct environment)
407
+ # Unset VIRTUAL_ENV to avoid conflicts with parent project's venv
408
+ env = os.environ.copy()
409
+ env.pop("VIRTUAL_ENV", None)
410
+
411
+ result = subprocess.run(
412
+ [
413
+ "uv",
414
+ "run",
415
+ "alembic",
416
+ "-c",
417
+ str(alembic_ini_path),
418
+ "upgrade",
419
+ "head",
420
+ ],
421
+ cwd=project_path,
422
+ capture_output=True,
423
+ text=True,
424
+ timeout=POST_GEN_TIMEOUT_MIGRATION,
425
+ env=env,
426
+ )
427
+
428
+ if result.returncode == 0:
429
+ print("āœ… Database tables created successfully")
430
+ return True
431
+ else:
432
+ print("āš ļø Database migration setup failed")
433
+ if result.stderr:
434
+ print(f" Error: {result.stderr.strip()}")
435
+ print("šŸ’” Run 'alembic upgrade head' manually after project creation")
436
+ return False
437
+
438
+ except subprocess.TimeoutExpired:
439
+ print("āš ļø Migration setup timeout - run 'alembic upgrade head' manually")
440
+ return False
441
+ except Exception as e:
442
+ print(f"āš ļø Migration setup failed: {e}")
443
+ print("šŸ’” Run 'alembic upgrade head' manually after project creation")
444
+ return False
445
+
446
+
447
+ def format_code(project_path: Path) -> bool:
448
+ """
449
+ Auto-format generated code using make fix.
450
+
451
+ Args:
452
+ project_path: Path to the project directory
453
+
454
+ Returns:
455
+ True if formatting succeeded, False otherwise
456
+ """
457
+ try:
458
+ print("šŸŽØ Auto-formatting generated code...")
459
+
460
+ # Call make fix to auto-format the generated project
461
+ # Unset VIRTUAL_ENV to avoid conflicts with parent project's venv
462
+ env = os.environ.copy()
463
+ env.pop("VIRTUAL_ENV", None)
464
+
465
+ result = subprocess.run(
466
+ ["make", "fix"],
467
+ cwd=project_path,
468
+ capture_output=True,
469
+ text=True,
470
+ timeout=POST_GEN_TIMEOUT_FORMAT,
471
+ env=env,
472
+ )
473
+
474
+ if result.returncode == 0:
475
+ print("āœ… Code formatting completed successfully")
476
+ return True
477
+ else:
478
+ print(
479
+ "āš ļø Some formatting issues detected, but project created successfully"
480
+ )
481
+ print("šŸ’” Run 'make fix' manually to resolve remaining issues")
482
+ return False
483
+
484
+ except FileNotFoundError:
485
+ print("šŸ’” Run 'make fix' to format code when ready")
486
+ return False
487
+ except subprocess.TimeoutExpired:
488
+ print("āš ļø Formatting timeout - run 'make fix' manually when ready")
489
+ return False
490
+ except Exception as e:
491
+ print(f"āš ļø Auto-formatting skipped: {e}")
492
+ print("šŸ’” Run 'make fix' manually to format code")
493
+ return False
494
+
495
+
496
+ def run_post_generation_tasks(project_path: Path, include_auth: bool = False) -> bool:
497
+ """
498
+ Run all post-generation tasks for a project.
499
+
500
+ This is the main entry point called by both Cookiecutter hooks
501
+ and Copier updaters.
502
+
503
+ Args:
504
+ project_path: Path to the generated/updated project
505
+ include_auth: Whether auth service is enabled (triggers migrations)
506
+
507
+ Returns:
508
+ True if all critical tasks succeeded, False otherwise
509
+
510
+ Note:
511
+ Individual task failures don't stop execution - we try to complete
512
+ as many tasks as possible and report what needs manual intervention.
513
+ """
514
+ print("\nšŸš€ Setting up your project environment...")
515
+
516
+ # Task 1: Install dependencies (critical)
517
+ deps_success = install_dependencies(project_path)
518
+
519
+ # Task 2: Setup .env file (non-critical)
520
+ setup_env_file(project_path)
521
+
522
+ # Task 3: Run migrations if auth enabled (non-critical)
523
+ run_migrations(project_path, include_auth)
524
+
525
+ # Task 4: Format code (non-critical)
526
+ format_code(project_path)
527
+
528
+ # Print final status
529
+ print("\n" + "=" * 60)
530
+ if deps_success:
531
+ print("āœ… Project ready to run!")
532
+ print("\nšŸ“‹ Next steps:")
533
+ print(f" cd {project_path.name}")
534
+ print(" make server")
535
+ print("\nšŸ’” Your application is fully configured and ready to use!")
536
+ else:
537
+ print("āš ļø Project created with some setup issues")
538
+ print("\nšŸ“‹ Manual setup required:")
539
+ print(f" cd {project_path.name}")
540
+ print(" uv sync")
541
+ print(" cp .env.example .env")
542
+ if include_auth:
543
+ print(" alembic upgrade head")
544
+ print(" make server")
545
+ print("=" * 60)
546
+
547
+ return deps_success