devctl 1.0.0__tar.gz → 1.2.1__tar.gz

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 (158) hide show
  1. {devctl-1.0.0 → devctl-1.2.1}/PKG-INFO +34 -4
  2. {devctl-1.0.0 → devctl-1.2.1}/README.md +31 -3
  3. {devctl-1.0.0 → devctl-1.2.1}/devctl/commands/add.py +11 -11
  4. {devctl-1.0.0 → devctl-1.2.1}/devctl/commands/deploy.py +2 -1
  5. {devctl-1.0.0 → devctl-1.2.1}/devctl/commands/docker.py +1 -1
  6. {devctl-1.0.0 → devctl-1.2.1}/devctl/commands/init.py +0 -3
  7. {devctl-1.0.0 → devctl-1.2.1}/devctl/commands/run.py +1 -1
  8. devctl-1.2.1/devctl/commands/tui.py +32 -0
  9. devctl-1.2.1/devctl/generators/angular/__init__.py +8 -0
  10. devctl-1.0.0/devctl/generators/angular.py → devctl-1.2.1/devctl/generators/angular/generator.py +11 -3
  11. devctl-1.0.0/devctl/generators/scaffold_angular.py → devctl-1.2.1/devctl/generators/angular/scaffolder.py +1 -1
  12. devctl-1.2.1/devctl/generators/django/__init__.py +8 -0
  13. devctl-1.2.1/devctl/generators/django/generator.py +90 -0
  14. devctl-1.0.0/devctl/generators/scaffold_django.py → devctl-1.2.1/devctl/generators/django/scaffolder.py +16 -28
  15. devctl-1.2.1/devctl/generators/django/templates/config/requirements.txt.j2 +3 -0
  16. devctl-1.2.1/devctl/generators/django/templates/resource/model.py.j2 +7 -0
  17. devctl-1.2.1/devctl/generators/django/templates/resource/serializer.py.j2 +4 -0
  18. devctl-1.2.1/devctl/generators/django/templates/resource/view.py.j2 +7 -0
  19. devctl-1.2.1/devctl/generators/docker/__init__.py +19 -0
  20. devctl-1.0.0/devctl/generators/docker_scaffold.py → devctl-1.2.1/devctl/generators/docker/scaffolder.py +2 -2
  21. devctl-1.2.1/devctl/generators/fastapi/__init__.py +8 -0
  22. devctl-1.0.0/devctl/generators/fastapi.py → devctl-1.2.1/devctl/generators/fastapi/generator.py +24 -23
  23. devctl-1.0.0/devctl/generators/scaffold_fastapi.py → devctl-1.2.1/devctl/generators/fastapi/scaffolder.py +14 -35
  24. devctl-1.2.1/devctl/generators/fastapi/templates/config/main.py.j2 +11 -0
  25. devctl-1.2.1/devctl/generators/fastapi/templates/config/requirements.txt.j2 +3 -0
  26. devctl-1.2.1/devctl/generators/fastapi/templates/resource/router.py.j2 +16 -0
  27. devctl-1.2.1/devctl/generators/fastapi/templates/resource/schema.py.j2 +15 -0
  28. devctl-1.2.1/devctl/generators/go_fiber/__init__.py +8 -0
  29. devctl-1.0.0/devctl/generators/go_fiber.py → devctl-1.2.1/devctl/generators/go_fiber/generator.py +16 -19
  30. devctl-1.0.0/devctl/generators/scaffold_go.py → devctl-1.2.1/devctl/generators/go_fiber/scaffolder.py +14 -23
  31. devctl-1.2.1/devctl/generators/go_fiber/templates/config/main.go.j2 +16 -0
  32. devctl-1.2.1/devctl/generators/go_fiber/templates/resource/handler.go.j2 +13 -0
  33. devctl-1.2.1/devctl/generators/go_fiber/templates/resource/model.go.j2 +6 -0
  34. devctl-1.2.1/devctl/generators/nestjs/__init__.py +8 -0
  35. devctl-1.0.0/devctl/generators/nestjs.py → devctl-1.2.1/devctl/generators/nestjs/generator.py +4 -0
  36. devctl-1.0.0/devctl/generators/scaffold_nestjs.py → devctl-1.2.1/devctl/generators/nestjs/scaffolder.py +4 -0
  37. devctl-1.2.1/devctl/generators/nextjs/__init__.py +8 -0
  38. devctl-1.0.0/devctl/generators/nextjs.py → devctl-1.2.1/devctl/generators/nextjs/generator.py +4 -0
  39. devctl-1.0.0/devctl/generators/scaffold_nextjs.py → devctl-1.2.1/devctl/generators/nextjs/scaffolder.py +13 -29
  40. devctl-1.2.1/devctl/generators/nextjs/templates/resource/component.tsx.j2 +14 -0
  41. devctl-1.2.1/devctl/generators/nextjs/templates/resource/page.tsx.j2 +11 -0
  42. devctl-1.2.1/devctl/generators/nodejs/__init__.py +8 -0
  43. devctl-1.0.0/devctl/generators/nodejs.py → devctl-1.2.1/devctl/generators/nodejs/generator.py +23 -23
  44. devctl-1.0.0/devctl/generators/scaffold_nodejs.py → devctl-1.2.1/devctl/generators/nodejs/scaffolder.py +13 -36
  45. devctl-1.2.1/devctl/generators/nodejs/templates/config/index.ts.j2 +17 -0
  46. devctl-1.2.1/devctl/generators/nodejs/templates/resource/controller.ts.j2 +18 -0
  47. devctl-1.2.1/devctl/generators/nodejs/templates/resource/routes.ts.j2 +10 -0
  48. devctl-1.2.1/devctl/generators/react/__init__.py +8 -0
  49. devctl-1.0.0/devctl/generators/react.py → devctl-1.2.1/devctl/generators/react/generator.py +10 -1
  50. devctl-1.0.0/devctl/generators/scaffold_react.py → devctl-1.2.1/devctl/generators/react/scaffolder.py +15 -36
  51. devctl-1.2.1/devctl/generators/react/templates/resource/component.tsx.j2 +19 -0
  52. devctl-1.2.1/devctl/generators/react/templates/resource/service.ts.j2 +13 -0
  53. devctl-1.2.1/devctl/generators/spring/__init__.py +11 -0
  54. devctl-1.0.0/devctl/generators/spring.py → devctl-1.2.1/devctl/generators/spring/generator.py +1 -1
  55. devctl-1.0.0/devctl/generators/scaffold_spring.py → devctl-1.2.1/devctl/generators/spring/scaffolder.py +2 -2
  56. devctl-1.2.1/devctl/generators/svelte/__init__.py +8 -0
  57. devctl-1.0.0/devctl/generators/svelte.py → devctl-1.2.1/devctl/generators/svelte/generator.py +10 -1
  58. devctl-1.0.0/devctl/generators/scaffold_svelte.py → devctl-1.2.1/devctl/generators/svelte/scaffolder.py +14 -29
  59. devctl-1.2.1/devctl/generators/svelte/templates/resource/component.svelte.j2 +18 -0
  60. devctl-1.2.1/devctl/generators/svelte/templates/resource/page.svelte.j2 +7 -0
  61. devctl-1.2.1/devctl/generators/vue/__init__.py +8 -0
  62. devctl-1.0.0/devctl/generators/vue.py → devctl-1.2.1/devctl/generators/vue/generator.py +17 -3
  63. devctl-1.0.0/devctl/generators/scaffold_vue.py → devctl-1.2.1/devctl/generators/vue/scaffolder.py +2 -2
  64. {devctl-1.0.0 → devctl-1.2.1}/devctl/main.py +2 -1
  65. devctl-1.2.1/devctl/orchestrator/process_manager.py +261 -0
  66. {devctl-1.0.0 → devctl-1.2.1}/devctl/orchestrator/runner.py +17 -13
  67. devctl-1.2.1/devctl/tui/app.py +810 -0
  68. devctl-1.2.1/devctl/utils/__init__.py +5 -0
  69. {devctl-1.0.0 → devctl-1.2.1}/devctl/utils/dependencies.py +12 -1
  70. devctl-1.2.1/devctl/utils/platform.py +120 -0
  71. {devctl-1.0.0 → devctl-1.2.1}/devctl.egg-info/PKG-INFO +34 -4
  72. devctl-1.2.1/devctl.egg-info/SOURCES.txt +142 -0
  73. {devctl-1.0.0 → devctl-1.2.1}/devctl.egg-info/requires.txt +2 -0
  74. {devctl-1.0.0 → devctl-1.2.1}/pyproject.toml +5 -3
  75. {devctl-1.0.0 → devctl-1.2.1}/test/test_env_loader.py +6 -6
  76. devctl-1.2.1/test/test_platform.py +68 -0
  77. {devctl-1.0.0 → devctl-1.2.1}/test/test_runner.py +1 -1
  78. devctl-1.2.1/test/test_tui.py +90 -0
  79. devctl-1.0.0/devctl/generators/django.py +0 -61
  80. devctl-1.0.0/devctl/templates/angular/config/proxy.conf.json.j2 +0 -8
  81. devctl-1.0.0/devctl/utils/__init__.py +0 -3
  82. devctl-1.0.0/devctl.egg-info/SOURCES.txt +0 -115
  83. devctl-1.0.0/test/test_django.py +0 -43
  84. devctl-1.0.0/test/test_docker_scaffold.py +0 -136
  85. devctl-1.0.0/test/test_fastapi.py +0 -41
  86. devctl-1.0.0/test/test_go.py +0 -40
  87. devctl-1.0.0/test/test_nestjs.py +0 -46
  88. devctl-1.0.0/test/test_nextjs.py +0 -40
  89. devctl-1.0.0/test/test_nodejs.py +0 -40
  90. devctl-1.0.0/test/test_pom_patcher.py +0 -52
  91. devctl-1.0.0/test/test_react.py +0 -44
  92. devctl-1.0.0/test/test_svelte.py +0 -40
  93. {devctl-1.0.0 → devctl-1.2.1}/LICENSE +0 -0
  94. {devctl-1.0.0 → devctl-1.2.1}/devctl/__init__.py +0 -0
  95. {devctl-1.0.0 → devctl-1.2.1}/devctl/commands/__init__.py +0 -0
  96. {devctl-1.0.0 → devctl-1.2.1}/devctl/generators/__init__.py +0 -0
  97. {devctl-1.0.0/devctl/templates/angular → devctl-1.2.1/devctl/generators/angular/templates}/config/environment.development.ts.j2 +0 -0
  98. {devctl-1.0.0/devctl/templates/angular → devctl-1.2.1/devctl/generators/angular/templates}/config/environment.ts.j2 +0 -0
  99. {devctl-1.0.0/devctl/templates → devctl-1.2.1/devctl/generators/angular/templates/config}/proxy.conf.json.j2 +0 -0
  100. {devctl-1.0.0/devctl/templates/angular → devctl-1.2.1/devctl/generators/angular/templates}/feature/models/request.model.ts.j2 +0 -0
  101. {devctl-1.0.0/devctl/templates/angular → devctl-1.2.1/devctl/generators/angular/templates}/feature/models/response.model.ts.j2 +0 -0
  102. {devctl-1.0.0/devctl/templates/angular → devctl-1.2.1/devctl/generators/angular/templates}/feature/pages/form/form.component.html.j2 +0 -0
  103. {devctl-1.0.0/devctl/templates/angular → devctl-1.2.1/devctl/generators/angular/templates}/feature/pages/form/form.component.scss.j2 +0 -0
  104. {devctl-1.0.0/devctl/templates/angular → devctl-1.2.1/devctl/generators/angular/templates}/feature/pages/form/form.component.ts.j2 +0 -0
  105. {devctl-1.0.0/devctl/templates/angular → devctl-1.2.1/devctl/generators/angular/templates}/feature/pages/list/list.component.html.j2 +0 -0
  106. {devctl-1.0.0/devctl/templates/angular → devctl-1.2.1/devctl/generators/angular/templates}/feature/pages/list/list.component.scss.j2 +0 -0
  107. {devctl-1.0.0/devctl/templates/angular → devctl-1.2.1/devctl/generators/angular/templates}/feature/pages/list/list.component.ts.j2 +0 -0
  108. {devctl-1.0.0/devctl/templates/angular → devctl-1.2.1/devctl/generators/angular/templates}/feature/routes.ts.j2 +0 -0
  109. {devctl-1.0.0/devctl/templates/angular → devctl-1.2.1/devctl/generators/angular/templates}/feature/services/service.ts.j2 +0 -0
  110. {devctl-1.0.0/devctl/templates/docker → devctl-1.2.1/devctl/generators/docker/templates}/deploy.yml.j2 +0 -0
  111. {devctl-1.0.0/devctl/templates/docker → devctl-1.2.1/devctl/generators/docker/templates}/django/Dockerfile.j2 +0 -0
  112. {devctl-1.0.0/devctl/templates/docker → devctl-1.2.1/devctl/generators/docker/templates}/fastapi/Dockerfile.j2 +0 -0
  113. {devctl-1.0.0/devctl/templates/docker → devctl-1.2.1/devctl/generators/docker/templates}/frontend/Dockerfile.j2 +0 -0
  114. {devctl-1.0.0/devctl/templates/docker → devctl-1.2.1/devctl/generators/docker/templates}/go/Dockerfile.j2 +0 -0
  115. {devctl-1.0.0/devctl/templates/docker → devctl-1.2.1/devctl/generators/docker/templates}/nestjs/Dockerfile.j2 +0 -0
  116. {devctl-1.0.0/devctl/templates/docker → devctl-1.2.1/devctl/generators/docker/templates}/nextjs/Dockerfile.j2 +0 -0
  117. {devctl-1.0.0/devctl/templates/docker → devctl-1.2.1/devctl/generators/docker/templates}/nodejs/Dockerfile.j2 +0 -0
  118. {devctl-1.0.0/devctl/templates/docker → devctl-1.2.1/devctl/generators/docker/templates}/spring/Dockerfile.j2 +0 -0
  119. {devctl-1.0.0/devctl/templates/docker → devctl-1.2.1/devctl/generators/docker/templates}/svelte/Dockerfile.j2 +0 -0
  120. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/Controller.java.j2 +0 -0
  121. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/Entity.java.j2 +0 -0
  122. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/Repository.java.j2 +0 -0
  123. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/Service.java.j2 +0 -0
  124. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/ServiceImpl.java.j2 +0 -0
  125. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/application.properties.j2 +0 -0
  126. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/config/ApplicationConfig.java.j2 +0 -0
  127. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/config/JwtAuthenticationFilter.java.j2 +0 -0
  128. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/config/JwtService.java.j2 +0 -0
  129. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/config/SecurityConfig.java.j2 +0 -0
  130. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/docker-compose.yml.j2 +0 -0
  131. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/dto/Request.java.j2 +0 -0
  132. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/dto/Response.java.j2 +0 -0
  133. {devctl-1.0.0/devctl/templates/spring → devctl-1.2.1/devctl/generators/spring/templates}/mapper/Mapper.java.j2 +0 -0
  134. {devctl-1.0.0/devctl/templates/vue → devctl-1.2.1/devctl/generators/vue/templates}/config/App.vue.j2 +0 -0
  135. {devctl-1.0.0/devctl/templates/vue → devctl-1.2.1/devctl/generators/vue/templates}/config/main.ts.j2 +0 -0
  136. {devctl-1.0.0/devctl/templates/vue → devctl-1.2.1/devctl/generators/vue/templates}/config/router.ts.j2 +0 -0
  137. {devctl-1.0.0/devctl/templates/vue → devctl-1.2.1/devctl/generators/vue/templates}/config/vite.config.ts.j2 +0 -0
  138. {devctl-1.0.0/devctl/templates/vue → devctl-1.2.1/devctl/generators/vue/templates}/feature/Form.vue.j2 +0 -0
  139. {devctl-1.0.0/devctl/templates/vue → devctl-1.2.1/devctl/generators/vue/templates}/feature/List.vue.j2 +0 -0
  140. {devctl-1.0.0/devctl/templates/vue → devctl-1.2.1/devctl/generators/vue/templates}/feature/models.ts.j2 +0 -0
  141. {devctl-1.0.0/devctl/templates/vue → devctl-1.2.1/devctl/generators/vue/templates}/feature/routes.ts.j2 +0 -0
  142. {devctl-1.0.0/devctl/templates/vue → devctl-1.2.1/devctl/generators/vue/templates}/feature/service.ts.j2 +0 -0
  143. {devctl-1.0.0 → devctl-1.2.1}/devctl/orchestrator/__init__.py +0 -0
  144. {devctl-1.0.0 → devctl-1.2.1}/devctl/orchestrator/config_builder.py +0 -0
  145. {devctl-1.0.0 → devctl-1.2.1}/devctl/orchestrator/scanner.py +0 -0
  146. {devctl-1.0.0 → devctl-1.2.1}/devctl/utils/env_loader.py +0 -0
  147. {devctl-1.0.0 → devctl-1.2.1}/devctl.egg-info/dependency_links.txt +0 -0
  148. {devctl-1.0.0 → devctl-1.2.1}/devctl.egg-info/entry_points.txt +0 -0
  149. {devctl-1.0.0 → devctl-1.2.1}/devctl.egg-info/top_level.txt +0 -0
  150. {devctl-1.0.0 → devctl-1.2.1}/setup.cfg +0 -0
  151. {devctl-1.0.0 → devctl-1.2.1}/test/test_add.py +0 -0
  152. {devctl-1.0.0 → devctl-1.2.1}/test/test_commands.py +0 -0
  153. {devctl-1.0.0 → devctl-1.2.1}/test/test_deploy.py +0 -0
  154. {devctl-1.0.0 → devctl-1.2.1}/test/test_init.py +0 -0
  155. {devctl-1.0.0 → devctl-1.2.1}/test/test_main.py +0 -0
  156. {devctl-1.0.0 → devctl-1.2.1}/test/test_mongodb.py +0 -0
  157. {devctl-1.0.0 → devctl-1.2.1}/test/test_scanner.py +0 -0
  158. {devctl-1.0.0 → devctl-1.2.1}/test/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devctl
3
- Version: 1.0.0
3
+ Version: 1.2.1
4
4
  Summary: Local development orchestrator for Spring Boot, Angular, and Vue.js
5
5
  Author: Youssef Fellah
6
6
  License: MIT License
@@ -37,6 +37,8 @@ Requires-Dist: requests>=2.31.0
37
37
  Requires-Dist: jinja2>=3.1.3
38
38
  Requires-Dist: rich>=13.7.0
39
39
  Requires-Dist: pyyaml>=6.0.1
40
+ Requires-Dist: textual>=0.80.0
41
+ Requires-Dist: psutil>=5.9.0
40
42
  Dynamic: license-file
41
43
 
42
44
  # devctl
@@ -45,10 +47,11 @@ Dynamic: license-file
45
47
  orchestrate the development lifecycle for modern full-stack architectures. It
46
48
  provides a unified workflow for managing backends (Spring Boot, NestJS, Go,
47
49
  FastAPI), frontends (Angular, Vue, React, NextJS, Svelte), and their
48
- containerization.
50
+ containerization across Linux, macOS, and Windows.
49
51
 
50
52
  ## Core Features
51
53
 
54
+ - **Cross-Platform Architecture**: Out-of-the-box support for Windows, Linux, and macOS utilizing a robust platform abstraction layer.
52
55
  - **Multi-Stack Orchestration**: Launch databases, multiple microservices, and
53
56
  frontend dev servers with a single command. Includes real-time, prefixed log
54
57
  streaming.
@@ -58,9 +61,34 @@ containerization.
58
61
  - **Instant Infrastructure**: Automatically generate optimized, multi-stage
59
62
  `Dockerfiles` and global `docker-compose-prod.yml` configurations by scanning
60
63
  your project tree.
64
+ - **Interactive Dashboard**: Real-time system monitoring (CPU/RAM/Disk) and service orchestration with side-by-side log streaming (`devctl tui`).
61
65
  - **Security by Default**: Inject standardized JWT authentication and security
62
66
  configurations into new projects.
63
67
 
68
+ ## Interactive Dashboard (TUI)
69
+
70
+ Launch the real-time terminal dashboard using `devctl tui`:
71
+
72
+ ### Dashboard & System Monitoring
73
+ ![Dashboard View](screenshots/tui_dashboard.png)
74
+
75
+ ### Real-Time Service Controls & Log Streaming
76
+ ![Services Control View](screenshots/tui_services_control.png)
77
+
78
+ <details>
79
+ <summary><b>View More TUI Views (Docker, Scaffolding, Project Init)</b></summary>
80
+
81
+ #### Docker Tools
82
+ ![Docker Scaffolding](screenshots/tui_docker_tools.png)
83
+
84
+ #### Vertical Resource Generator
85
+ ![Add Resource Generator](screenshots/tui_add_resource.png)
86
+
87
+ #### Project Initializer
88
+ ![Init Project Generator](screenshots/tui_init_project.png)
89
+
90
+ </details>
91
+
64
92
  ## Installation
65
93
 
66
94
  You can install `devctl` locally for development:
@@ -109,8 +137,10 @@ devctl run
109
137
 
110
138
  ## Documentation
111
139
 
112
- For a detailed reference of all available commands and their options, see the
113
- [Commands Reference](COMMANDS.md).
140
+ * For a detailed reference of all available commands and their options, see the
141
+ [Commands Reference](COMMANDS.md).
142
+ * For an overview of the internal code structures and process pipelines, see the
143
+ [Architecture Guide](ARCHITECTURE.md).
114
144
 
115
145
  ## Contributing
116
146
 
@@ -4,10 +4,11 @@
4
4
  orchestrate the development lifecycle for modern full-stack architectures. It
5
5
  provides a unified workflow for managing backends (Spring Boot, NestJS, Go,
6
6
  FastAPI), frontends (Angular, Vue, React, NextJS, Svelte), and their
7
- containerization.
7
+ containerization across Linux, macOS, and Windows.
8
8
 
9
9
  ## Core Features
10
10
 
11
+ - **Cross-Platform Architecture**: Out-of-the-box support for Windows, Linux, and macOS utilizing a robust platform abstraction layer.
11
12
  - **Multi-Stack Orchestration**: Launch databases, multiple microservices, and
12
13
  frontend dev servers with a single command. Includes real-time, prefixed log
13
14
  streaming.
@@ -17,9 +18,34 @@ containerization.
17
18
  - **Instant Infrastructure**: Automatically generate optimized, multi-stage
18
19
  `Dockerfiles` and global `docker-compose-prod.yml` configurations by scanning
19
20
  your project tree.
21
+ - **Interactive Dashboard**: Real-time system monitoring (CPU/RAM/Disk) and service orchestration with side-by-side log streaming (`devctl tui`).
20
22
  - **Security by Default**: Inject standardized JWT authentication and security
21
23
  configurations into new projects.
22
24
 
25
+ ## Interactive Dashboard (TUI)
26
+
27
+ Launch the real-time terminal dashboard using `devctl tui`:
28
+
29
+ ### Dashboard & System Monitoring
30
+ ![Dashboard View](screenshots/tui_dashboard.png)
31
+
32
+ ### Real-Time Service Controls & Log Streaming
33
+ ![Services Control View](screenshots/tui_services_control.png)
34
+
35
+ <details>
36
+ <summary><b>View More TUI Views (Docker, Scaffolding, Project Init)</b></summary>
37
+
38
+ #### Docker Tools
39
+ ![Docker Scaffolding](screenshots/tui_docker_tools.png)
40
+
41
+ #### Vertical Resource Generator
42
+ ![Add Resource Generator](screenshots/tui_add_resource.png)
43
+
44
+ #### Project Initializer
45
+ ![Init Project Generator](screenshots/tui_init_project.png)
46
+
47
+ </details>
48
+
23
49
  ## Installation
24
50
 
25
51
  You can install `devctl` locally for development:
@@ -68,8 +94,10 @@ devctl run
68
94
 
69
95
  ## Documentation
70
96
 
71
- For a detailed reference of all available commands and their options, see the
72
- [Commands Reference](COMMANDS.md).
97
+ * For a detailed reference of all available commands and their options, see the
98
+ [Commands Reference](COMMANDS.md).
99
+ * For an overview of the internal code structures and process pipelines, see the
100
+ [Architecture Guide](ARCHITECTURE.md).
73
101
 
74
102
  ## Contributing
75
103
 
@@ -8,17 +8,17 @@ import os
8
8
 
9
9
  import typer
10
10
 
11
- from devctl.generators.scaffold_angular import generate_angular_resource
12
- from devctl.generators.scaffold_django import generate_django_resource
13
- from devctl.generators.scaffold_fastapi import generate_fastapi_resource
14
- from devctl.generators.scaffold_go import generate_go_resource
15
- from devctl.generators.scaffold_nestjs import generate_nest_resource
16
- from devctl.generators.scaffold_nextjs import generate_nextjs_resource
17
- from devctl.generators.scaffold_nodejs import generate_nodejs_resource
18
- from devctl.generators.scaffold_react import generate_react_resource
19
- from devctl.generators.scaffold_spring import generate_spring_resource
20
- from devctl.generators.scaffold_svelte import generate_svelte_resource
21
- from devctl.generators.scaffold_vue import generate_vue_resource
11
+ from devctl.generators.angular import generate_angular_resource
12
+ from devctl.generators.django import generate_django_resource
13
+ from devctl.generators.fastapi import generate_fastapi_resource
14
+ from devctl.generators.go_fiber import generate_go_resource
15
+ from devctl.generators.nestjs import generate_nest_resource
16
+ from devctl.generators.nextjs import generate_nextjs_resource
17
+ from devctl.generators.nodejs import generate_nodejs_resource
18
+ from devctl.generators.react import generate_react_resource
19
+ from devctl.generators.spring import generate_spring_resource
20
+ from devctl.generators.svelte import generate_svelte_resource
21
+ from devctl.generators.vue import generate_vue_resource
22
22
  from devctl.orchestrator.scanner import detect_environment
23
23
  from devctl.utils.dependencies import check_tool
24
24
 
@@ -2,7 +2,7 @@ from pathlib import Path
2
2
 
3
3
  import typer
4
4
 
5
- from devctl.generators.docker_scaffold import (
5
+ from devctl.generators.docker import (
6
6
  DockerScaffoldError,
7
7
  scaffold_docker_assets,
8
8
  )
@@ -20,6 +20,7 @@ FORCE_OPTION = typer.Option(
20
20
  help="Overwrite generated Docker files that already exist.",
21
21
  )
22
22
 
23
+
23
24
  @app.command()
24
25
  def deploy(
25
26
  path: Path = PATH_ARGUMENT,
@@ -7,7 +7,7 @@ from pathlib import Path
7
7
 
8
8
  import typer
9
9
 
10
- from devctl.generators.docker_scaffold import (
10
+ from devctl.generators.docker import (
11
11
  DockerScaffoldError,
12
12
  scaffold_docker_assets,
13
13
  )
@@ -6,7 +6,6 @@ Django, Svelte, and Go.
6
6
 
7
7
  import typer
8
8
 
9
- # Angular generator
10
9
  from devctl.generators.angular import generate_angular_boilerplate
11
10
  from devctl.generators.django import generate_django_boilerplate
12
11
  from devctl.generators.fastapi import generate_fastapi_boilerplate
@@ -15,8 +14,6 @@ from devctl.generators.nestjs import generate_nest_boilerplate
15
14
  from devctl.generators.nextjs import generate_nextjs_boilerplate
16
15
  from devctl.generators.nodejs import generate_nodejs_boilerplate
17
16
  from devctl.generators.react import generate_react_boilerplate
18
-
19
- # Spring generator
20
17
  from devctl.generators.spring import download_spring_boilerplate
21
18
  from devctl.generators.svelte import generate_svelte_boilerplate
22
19
  from devctl.generators.vue import generate_vue_boilerplate
@@ -7,7 +7,7 @@ from pathlib import Path
7
7
 
8
8
  import typer
9
9
 
10
- from devctl.generators.docker_scaffold import discover_docker_projects
10
+ from devctl.generators.docker import discover_docker_projects
11
11
  from devctl.orchestrator.runner import launch_dev_environment
12
12
  from devctl.utils.dependencies import check_tool
13
13
 
@@ -0,0 +1,32 @@
1
+ """
2
+ CLI command group for launching the interactive TUI.
3
+ """
4
+
5
+ import typer
6
+
7
+ app = typer.Typer(help="Interactive Terminal User Interface.")
8
+
9
+
10
+ @app.callback(invoke_without_command=True)
11
+ def launch_tui(
12
+ ctx: typer.Context,
13
+ single: bool = typer.Option(
14
+ False, "--single", "-s", help="Launch the single-panel dashboard layout."
15
+ ),
16
+ ):
17
+ """
18
+ Launches the interactive btop-like management interface.
19
+ """
20
+ if ctx.invoked_subcommand is not None:
21
+ return
22
+
23
+ typer.secho("Initializing interactive Devctl TUI...", fg=typer.colors.CYAN)
24
+
25
+ try:
26
+ from devctl.tui.app import DevctlTUI
27
+
28
+ tui_app = DevctlTUI(single_panel=single)
29
+ tui_app.run()
30
+ except Exception as e:
31
+ typer.secho(f"Error launching TUI: {e}", fg=typer.colors.RED)
32
+ raise typer.Exit(code=1) from e
@@ -0,0 +1,8 @@
1
+ """
2
+ Angular framework generator and scaffolder.
3
+ """
4
+
5
+ from devctl.generators.angular.generator import generate_angular_boilerplate
6
+ from devctl.generators.angular.scaffolder import generate_angular_resource
7
+
8
+ __all__ = ["generate_angular_boilerplate", "generate_angular_resource"]
@@ -23,7 +23,7 @@ def setup_angular_environments(project_path: str):
23
23
  os.makedirs(env_dir, exist_ok=True)
24
24
 
25
25
  # 2. Template rendering via Jinja2
26
- templates_dir = os.path.join(os.path.dirname(__file__), "..", "templates", "angular", "config")
26
+ templates_dir = os.path.join(os.path.dirname(__file__), "templates", "config")
27
27
  env = Environment(loader=FileSystemLoader(templates_dir))
28
28
 
29
29
  files_to_generate = {
@@ -79,8 +79,16 @@ def generate_angular_boilerplate(project_name: str) -> bool:
79
79
 
80
80
  safe_name = project_name.lower().replace("_", "-")
81
81
 
82
+ from ...utils import get_platform
83
+
84
+ platform = get_platform()
82
85
  try:
83
- subprocess.run(["ng", "version"], capture_output=True, check=True)
86
+ subprocess.run(
87
+ ["ng", "version"],
88
+ capture_output=True,
89
+ check=True,
90
+ shell=platform.shell_required,
91
+ )
84
92
  except FileNotFoundError:
85
93
  typer.secho(
86
94
  "Error: Angular CLI ('ng') not found on your system.",
@@ -95,7 +103,7 @@ def generate_angular_boilerplate(project_name: str) -> bool:
95
103
  command = ["ng", "new", safe_name, "--routing=true", "--style=scss", "--skip-git=true"]
96
104
 
97
105
  typer.secho("Downloading npm packages... (This may take 1-2 minutes)", fg=typer.colors.CYAN)
98
- subprocess.run(command, check=True)
106
+ subprocess.run(command, check=True, shell=platform.shell_required)
99
107
 
100
108
  # Post-installation configuration
101
109
  project_full_path = os.path.join(os.getcwd(), safe_name)
@@ -117,7 +117,7 @@ def generate_angular_resource(resource_name: str, fields_str: str, root_path: st
117
117
  },
118
118
  ]
119
119
 
120
- templates_dir = os.path.join(os.path.dirname(__file__), "..", "templates", "angular", "feature")
120
+ templates_dir = os.path.join(os.path.dirname(__file__), "templates", "feature")
121
121
  env = Environment(loader=FileSystemLoader(templates_dir))
122
122
 
123
123
  typer.secho(f"Generating Angular feature '{entity_name}'...", fg=typer.colors.CYAN)
@@ -0,0 +1,8 @@
1
+ """
2
+ Django framework generator and scaffolder.
3
+ """
4
+
5
+ from devctl.generators.django.generator import generate_django_boilerplate
6
+ from devctl.generators.django.scaffolder import generate_django_resource
7
+
8
+ __all__ = ["generate_django_boilerplate", "generate_django_resource"]
@@ -0,0 +1,90 @@
1
+ """
2
+ Generators for Django projects.
3
+ Includes boilerplate generation with Django and DRF.
4
+ """
5
+
6
+ import os
7
+ import subprocess
8
+ import sys
9
+
10
+ import typer
11
+ from jinja2 import Environment, FileSystemLoader
12
+
13
+
14
+ def generate_django_boilerplate(project_name: str) -> bool:
15
+ """
16
+ Generates a new Django project.
17
+ """
18
+ typer.secho(f"Generating Django project '{project_name}'...", fg=typer.colors.CYAN)
19
+ safe_name = project_name.lower().replace("-", "_") # Django prefers underscores
20
+ project_path = os.path.join(os.getcwd(), project_name)
21
+
22
+ try:
23
+ os.makedirs(project_path, exist_ok=True)
24
+
25
+ templates_dir = os.path.join(os.path.dirname(__file__), "templates", "config")
26
+ env = Environment(loader=FileSystemLoader(templates_dir))
27
+
28
+ # 1. Create requirements.txt
29
+ req_content = env.get_template("requirements.txt.j2").render()
30
+ with open(os.path.join(project_path, "requirements.txt"), "w", encoding="utf-8") as f:
31
+ f.write(req_content)
32
+
33
+ python_exe = "python" if sys.platform == "win32" else "python3"
34
+
35
+ # 2. Create virtual environment
36
+ typer.secho("Creating virtual environment...", fg=typer.colors.CYAN)
37
+ subprocess.run(
38
+ [python_exe, "-m", "venv", ".venv"],
39
+ cwd=project_path,
40
+ check=True,
41
+ shell=(sys.platform == "win32"),
42
+ )
43
+
44
+ # 3. Install Django
45
+ typer.secho("Installing Django and DRF...", fg=typer.colors.CYAN)
46
+ if sys.platform == "win32":
47
+ pip_path = os.path.join(".venv", "Scripts", "pip.exe")
48
+ else:
49
+ pip_path = os.path.join(".venv", "bin", "pip")
50
+ subprocess.run(
51
+ [pip_path, "install", "django", "djangorestframework"],
52
+ cwd=project_path,
53
+ check=True,
54
+ stdout=subprocess.DEVNULL,
55
+ shell=(sys.platform == "win32"),
56
+ )
57
+
58
+ # 4. Start Project
59
+ typer.secho("Scaffolding Django project structure...", fg=typer.colors.CYAN)
60
+ if sys.platform == "win32":
61
+ django_admin = os.path.join(".venv", "Scripts", "django-admin.exe")
62
+ else:
63
+ django_admin = os.path.join(".venv", "bin", "django-admin")
64
+ subprocess.run(
65
+ [django_admin, "startproject", safe_name, "."],
66
+ cwd=project_path,
67
+ check=True,
68
+ shell=(sys.platform == "win32"),
69
+ )
70
+
71
+ # 5. Create core app
72
+ if sys.platform == "win32":
73
+ python_path = os.path.join(".venv", "Scripts", "python.exe")
74
+ else:
75
+ python_path = os.path.join(".venv", "bin", "python")
76
+ subprocess.run(
77
+ [python_path, "manage.py", "startapp", "core"],
78
+ cwd=project_path,
79
+ check=True,
80
+ shell=(sys.platform == "win32"),
81
+ )
82
+
83
+ typer.secho(
84
+ f"Django project '{project_name}' successfully generated!", fg=typer.colors.GREEN
85
+ )
86
+ return True
87
+
88
+ except Exception as e:
89
+ typer.secho(f"Error: Django initialization failed: {e}", fg=typer.colors.RED)
90
+ return False
@@ -6,6 +6,7 @@ Handles the creation of models, serializers, and views.
6
6
  import os
7
7
 
8
8
  import typer
9
+ from jinja2 import Environment, FileSystemLoader
9
10
 
10
11
  from devctl.orchestrator.scanner import detect_environment
11
12
 
@@ -30,47 +31,34 @@ def generate_django_resource(resource_name: str, fields_str: str, root_path: str
30
31
  if not os.path.exists(core_dir):
31
32
  os.makedirs(core_dir, exist_ok=True)
32
33
 
34
+ templates_dir = os.path.join(os.path.dirname(__file__), "templates", "resource")
35
+ env = Environment(loader=FileSystemLoader(templates_dir))
36
+
33
37
  typer.secho(f"⚙️ Generating Django resource '{entity_name}'...", fg=typer.colors.CYAN)
34
38
 
39
+ context = {
40
+ "entity_name": entity_name,
41
+ "fields_str": fields_str,
42
+ }
43
+
35
44
  # 1. Append Model
36
- model_snippet = f"""
37
- class {entity_name}(models.Model):
38
- # Fields: {fields_str}
39
- created_at = models.DateTimeField(auto_now_add=True)
40
- updated_at = models.DateTimeField(auto_now=True)
41
-
42
- def __str__(self):
43
- return f"{entity_name} {{self.id}}"
44
- """
45
- with open(os.path.join(core_dir, "models.py"), "a") as f:
45
+ model_snippet = "\n" + env.get_template("model.py.j2").render(**context) + "\n"
46
+ with open(os.path.join(core_dir, "models.py"), "a", encoding="utf-8") as f:
46
47
  f.write(model_snippet)
47
48
 
48
49
  # 2. Append Serializer
49
50
  serializer_path = os.path.join(core_dir, "serializers.py")
50
51
  if not os.path.exists(serializer_path):
51
- with open(serializer_path, "w") as f:
52
+ with open(serializer_path, "w", encoding="utf-8") as f:
52
53
  f.write("from rest_framework import serializers\nfrom .models import *\n")
53
54
 
54
- serializer_snippet = f"""
55
- class {entity_name}Serializer(serializers.ModelSerializer):
56
- class Meta:
57
- model = {entity_name}
58
- fields = '__all__'
59
- """
60
- with open(serializer_path, "a") as f:
55
+ serializer_snippet = "\n" + env.get_template("serializer.py.j2").render(**context) + "\n"
56
+ with open(serializer_path, "a", encoding="utf-8") as f:
61
57
  f.write(serializer_snippet)
62
58
 
63
59
  # 3. Append View
64
- view_snippet = f"""
65
- from rest_framework import viewsets
66
- from .models import {entity_name}
67
- from .serializers import {entity_name}Serializer
68
-
69
- class {entity_name}ViewSet(viewsets.ModelViewSet):
70
- queryset = {entity_name}.objects.all()
71
- serializer_class = {entity_name}Serializer
72
- """
73
- with open(os.path.join(core_dir, "views.py"), "a") as f:
60
+ view_snippet = "\n" + env.get_template("view.py.j2").render(**context) + "\n"
61
+ with open(os.path.join(core_dir, "views.py"), "a", encoding="utf-8") as f:
74
62
  f.write(view_snippet)
75
63
 
76
64
  typer.secho(f"✅ {entity_name} Django feature successfully generated!", fg=typer.colors.GREEN)
@@ -0,0 +1,3 @@
1
+ django
2
+ djangorestframework
3
+ django-cors-headers
@@ -0,0 +1,7 @@
1
+ class {{ entity_name }}(models.Model):
2
+ # Fields: {{ fields_str }}
3
+ created_at = models.DateTimeField(auto_now_add=True)
4
+ updated_at = models.DateTimeField(auto_now=True)
5
+
6
+ def __str__(self):
7
+ return f"{{ entity_name }} {self.id}"
@@ -0,0 +1,4 @@
1
+ class {{ entity_name }}Serializer(serializers.ModelSerializer):
2
+ class Meta:
3
+ model = {{ entity_name }}
4
+ fields = '__all__'
@@ -0,0 +1,7 @@
1
+ from rest_framework import viewsets
2
+ from .models import {{ entity_name }}
3
+ from .serializers import {{ entity_name }}Serializer
4
+
5
+ class {{ entity_name }}ViewSet(viewsets.ModelViewSet):
6
+ queryset = {{ entity_name }}.objects.all()
7
+ serializer_class = {{ entity_name }}Serializer
@@ -0,0 +1,19 @@
1
+ """
2
+ Docker asset scaffolder.
3
+ """
4
+
5
+ from devctl.generators.docker.scaffolder import (
6
+ DockerProject,
7
+ DockerScaffoldError,
8
+ discover_docker_projects,
9
+ sanitize_service_name,
10
+ scaffold_docker_assets,
11
+ )
12
+
13
+ __all__ = [
14
+ "DockerProject",
15
+ "DockerScaffoldError",
16
+ "discover_docker_projects",
17
+ "sanitize_service_name",
18
+ "scaffold_docker_assets",
19
+ ]
@@ -257,7 +257,7 @@ def _generate_compose_content(projects: list[DockerProject]) -> str:
257
257
 
258
258
  services_data.append(service_dict)
259
259
 
260
- template_dir = Path(__file__).resolve().parent.parent / "templates" / "docker"
260
+ template_dir = Path(__file__).resolve().parent / "templates"
261
261
  env = Environment(
262
262
  loader=FileSystemLoader(str(template_dir)),
263
263
  trim_blocks=True,
@@ -501,7 +501,7 @@ def _write_file(path: Path, content: str, *, force: bool, dry_run: bool) -> File
501
501
 
502
502
 
503
503
  def _template_environment() -> Environment:
504
- template_dir = Path(__file__).resolve().parent.parent / "templates" / "docker"
504
+ template_dir = Path(__file__).resolve().parent / "templates"
505
505
  return Environment(
506
506
  loader=FileSystemLoader(str(template_dir)),
507
507
  trim_blocks=True,
@@ -0,0 +1,8 @@
1
+ """
2
+ FastAPI framework generator and scaffolder.
3
+ """
4
+
5
+ from devctl.generators.fastapi.generator import generate_fastapi_boilerplate
6
+ from devctl.generators.fastapi.scaffolder import generate_fastapi_resource
7
+
8
+ __all__ = ["generate_fastapi_boilerplate", "generate_fastapi_resource"]
@@ -5,8 +5,10 @@ Includes boilerplate generation with Uvicorn and Pydantic.
5
5
 
6
6
  import os
7
7
  import subprocess
8
+ import sys
8
9
 
9
10
  import typer
11
+ from jinja2 import Environment, FileSystemLoader
10
12
 
11
13
 
12
14
  def generate_fastapi_boilerplate(project_name: str) -> bool:
@@ -20,43 +22,42 @@ def generate_fastapi_boilerplate(project_name: str) -> bool:
20
22
  try:
21
23
  os.makedirs(project_path, exist_ok=True)
22
24
 
23
- # 1. Create main.py
24
- main_py = """from fastapi import FastAPI
25
-
26
- app = FastAPI(title="devctl FastAPI project")
27
-
28
- @app.get("/")
29
- def read_root():
30
- return {"Hello": "from devctl FastAPI!"}
25
+ templates_dir = os.path.join(os.path.dirname(__file__), "templates", "config")
26
+ env = Environment(loader=FileSystemLoader(templates_dir))
31
27
 
32
- @app.get("/items/{item_id}")
33
- def read_item(item_id: int, q: str = None):
34
- return {"item_id": item_id, "q": q}
35
- """
36
- with open(os.path.join(project_path, "main.py"), "w") as f:
37
- f.write(main_py)
28
+ # 1. Create main.py
29
+ main_content = env.get_template("main.py.j2").render()
30
+ with open(os.path.join(project_path, "main.py"), "w", encoding="utf-8") as f:
31
+ f.write(main_content)
38
32
 
39
33
  # 2. Create requirements.txt
40
- requirements = """fastapi
41
- uvicorn[standard]
42
- pydantic
43
- """
44
- with open(os.path.join(project_path, "requirements.txt"), "w") as f:
45
- f.write(requirements)
34
+ req_content = env.get_template("requirements.txt.j2").render()
35
+ with open(os.path.join(project_path, "requirements.txt"), "w", encoding="utf-8") as f:
36
+ f.write(req_content)
37
+
38
+ python_exe = "python" if sys.platform == "win32" else "python3"
46
39
 
47
40
  # 3. Create virtual environment
48
41
  typer.secho("Creating virtual environment...", fg=typer.colors.CYAN)
49
- subprocess.run(["python3", "-m", "venv", ".venv"], cwd=project_path, check=True)
42
+ subprocess.run(
43
+ [python_exe, "-m", "venv", ".venv"],
44
+ cwd=project_path,
45
+ check=True,
46
+ shell=(sys.platform == "win32"),
47
+ )
50
48
 
51
49
  # 4. Install dependencies
52
50
  typer.secho("Installing dependencies (fastapi, uvicorn)...", fg=typer.colors.CYAN)
53
- # Note: on Linux it's .venv/bin/pip
54
- pip_path = os.path.join(".venv", "bin", "pip")
51
+ if sys.platform == "win32":
52
+ pip_path = os.path.join(".venv", "Scripts", "pip.exe")
53
+ else:
54
+ pip_path = os.path.join(".venv", "bin", "pip")
55
55
  subprocess.run(
56
56
  [pip_path, "install", "-r", "requirements.txt"],
57
57
  cwd=project_path,
58
58
  check=True,
59
59
  stdout=subprocess.DEVNULL,
60
+ shell=(sys.platform == "win32"),
60
61
  )
61
62
 
62
63
  typer.secho(f"FastAPI project '{safe_name}' successfully generated!", fg=typer.colors.GREEN)