devctl 1.2.3__tar.gz → 1.2.4__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.
- {devctl-1.2.3 → devctl-1.2.4}/PKG-INFO +9 -4
- {devctl-1.2.3 → devctl-1.2.4}/README.md +7 -2
- {devctl-1.2.3 → devctl-1.2.4}/devctl/commands/init.py +25 -0
- devctl-1.2.4/devctl/generators/agent/__init__.py +7 -0
- devctl-1.2.4/devctl/generators/agent/generator.py +269 -0
- devctl-1.2.4/devctl/generators/agent/templates/AGENTS.md.j2 +87 -0
- devctl-1.2.4/devctl/generators/agent/templates/CLAUDE.md.j2 +8 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/tui/app.py +2 -0
- devctl-1.2.4/devctl/tui/app.tcss +353 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl.egg-info/PKG-INFO +9 -4
- {devctl-1.2.3 → devctl-1.2.4}/devctl.egg-info/SOURCES.txt +6 -0
- {devctl-1.2.3 → devctl-1.2.4}/pyproject.toml +3 -3
- devctl-1.2.4/test/test_agent_context.py +80 -0
- devctl-1.2.4/test/test_init.py +46 -0
- devctl-1.2.3/test/test_init.py +0 -33
- {devctl-1.2.3 → devctl-1.2.4}/LICENSE +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/commands/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/commands/add.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/commands/deploy.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/commands/docker.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/commands/run.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/commands/tui.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/generator.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/scaffolder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/config/environment.development.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/config/environment.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/config/proxy.conf.json.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/feature/models/request.model.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/feature/models/response.model.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/feature/pages/form/form.component.html.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/feature/pages/form/form.component.scss.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/feature/pages/form/form.component.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/feature/pages/list/list.component.html.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/feature/pages/list/list.component.scss.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/feature/pages/list/list.component.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/feature/routes.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/angular/templates/feature/services/service.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/django/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/django/generator.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/django/scaffolder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/django/templates/config/requirements.txt.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/django/templates/resource/model.py.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/django/templates/resource/serializer.py.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/django/templates/resource/view.py.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/docker/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/docker/scaffolder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/docker/templates/deploy.yml.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/docker/templates/django/Dockerfile.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/docker/templates/fastapi/Dockerfile.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/docker/templates/frontend/Dockerfile.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/docker/templates/go/Dockerfile.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/docker/templates/nestjs/Dockerfile.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/docker/templates/nextjs/Dockerfile.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/docker/templates/nodejs/Dockerfile.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/docker/templates/spring/Dockerfile.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/docker/templates/svelte/Dockerfile.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/fastapi/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/fastapi/generator.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/fastapi/scaffolder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/fastapi/templates/config/main.py.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/fastapi/templates/config/requirements.txt.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/fastapi/templates/resource/router.py.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/fastapi/templates/resource/schema.py.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/go_fiber/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/go_fiber/generator.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/go_fiber/scaffolder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/go_fiber/templates/config/main.go.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/go_fiber/templates/resource/handler.go.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/go_fiber/templates/resource/model.go.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nestjs/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nestjs/generator.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nestjs/scaffolder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nextjs/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nextjs/generator.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nextjs/scaffolder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nextjs/templates/resource/component.tsx.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nextjs/templates/resource/page.tsx.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nodejs/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nodejs/generator.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nodejs/scaffolder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nodejs/templates/config/index.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nodejs/templates/resource/controller.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/nodejs/templates/resource/routes.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/react/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/react/generator.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/react/scaffolder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/react/templates/resource/component.tsx.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/react/templates/resource/service.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/generator.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/scaffolder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/Controller.java.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/Entity.java.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/Repository.java.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/Service.java.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/ServiceImpl.java.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/application.properties.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/config/ApplicationConfig.java.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/config/JwtAuthenticationFilter.java.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/config/JwtService.java.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/config/SecurityConfig.java.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/docker-compose.yml.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/dto/Request.java.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/dto/Response.java.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/spring/templates/mapper/Mapper.java.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/svelte/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/svelte/generator.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/svelte/scaffolder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/svelte/templates/resource/component.svelte.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/svelte/templates/resource/page.svelte.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/vue/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/vue/generator.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/vue/scaffolder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/vue/templates/config/App.vue.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/vue/templates/config/main.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/vue/templates/config/router.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/vue/templates/config/vite.config.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/vue/templates/feature/Form.vue.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/vue/templates/feature/List.vue.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/vue/templates/feature/models.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/vue/templates/feature/routes.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/generators/vue/templates/feature/service.ts.j2 +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/main.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/orchestrator/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/orchestrator/config_builder.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/orchestrator/process_manager.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/orchestrator/runner.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/orchestrator/scanner.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/utils/__init__.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/utils/dependencies.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/utils/env_loader.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl/utils/platform.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl.egg-info/dependency_links.txt +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl.egg-info/entry_points.txt +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl.egg-info/requires.txt +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/devctl.egg-info/top_level.txt +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/setup.cfg +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/test/test_add.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/test/test_commands.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/test/test_deploy.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/test/test_env_loader.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/test/test_main.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/test/test_mongodb.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/test/test_platform.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/test/test_runner.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/test/test_scanner.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/test/test_tui.py +0 -0
- {devctl-1.2.3 → devctl-1.2.4}/test/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devctl
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.4
|
|
4
4
|
Summary: Local development orchestrator for Spring Boot, Angular, and Vue.js
|
|
5
5
|
Author: Youssef Fellah
|
|
6
6
|
License: MIT License
|
|
@@ -29,7 +29,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
29
29
|
Classifier: License :: OSI Approved :: MIT License
|
|
30
30
|
Classifier: Operating System :: OS Independent
|
|
31
31
|
Classifier: Topic :: Software Development :: Build Tools
|
|
32
|
-
Requires-Python: >=3.
|
|
32
|
+
Requires-Python: >=3.10
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
License-File: LICENSE
|
|
35
35
|
Requires-Dist: typer>=0.12.3
|
|
@@ -64,6 +64,9 @@ containerization across Linux, macOS, and Windows.
|
|
|
64
64
|
- **Interactive Dashboard**: Real-time system monitoring (CPU/RAM/Disk) and service orchestration with side-by-side log streaming (`devctl tui`).
|
|
65
65
|
- **Security by Default**: Inject standardized JWT authentication and security
|
|
66
66
|
configurations into new projects.
|
|
67
|
+
- **AI Agent Context Generation**: Automatically creates and updates `AGENTS.md`,
|
|
68
|
+
`CLAUDE.md`, and `.cursorrules` on project initialization, aligning coding agents
|
|
69
|
+
(Claude Code, Cursor, Copilot) with active ports, commands, and contract conventions.
|
|
67
70
|
|
|
68
71
|
## Interactive Dashboard (TUI)
|
|
69
72
|
|
|
@@ -153,5 +156,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
|
153
156
|
for details.
|
|
154
157
|
|
|
155
158
|
---
|
|
156
|
-
|
|
157
|
-
|
|
159
|
+
|
|
160
|
+
## Author
|
|
161
|
+
|
|
162
|
+
- **Author:** Youssef Fellah ([ind4x_](https://github.com/ind4x))
|
|
@@ -21,6 +21,9 @@ containerization across Linux, macOS, and Windows.
|
|
|
21
21
|
- **Interactive Dashboard**: Real-time system monitoring (CPU/RAM/Disk) and service orchestration with side-by-side log streaming (`devctl tui`).
|
|
22
22
|
- **Security by Default**: Inject standardized JWT authentication and security
|
|
23
23
|
configurations into new projects.
|
|
24
|
+
- **AI Agent Context Generation**: Automatically creates and updates `AGENTS.md`,
|
|
25
|
+
`CLAUDE.md`, and `.cursorrules` on project initialization, aligning coding agents
|
|
26
|
+
(Claude Code, Cursor, Copilot) with active ports, commands, and contract conventions.
|
|
24
27
|
|
|
25
28
|
## Interactive Dashboard (TUI)
|
|
26
29
|
|
|
@@ -110,5 +113,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
|
110
113
|
for details.
|
|
111
114
|
|
|
112
115
|
---
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
|
|
117
|
+
## Author
|
|
118
|
+
|
|
119
|
+
- **Author:** Youssef Fellah ([ind4x_](https://github.com/ind4x))
|
|
@@ -6,6 +6,7 @@ Django, Svelte, and Go.
|
|
|
6
6
|
|
|
7
7
|
import typer
|
|
8
8
|
|
|
9
|
+
from devctl.generators.agent import generate_agent_context
|
|
9
10
|
from devctl.generators.angular import generate_angular_boilerplate
|
|
10
11
|
from devctl.generators.django import generate_django_boilerplate
|
|
11
12
|
from devctl.generators.fastapi import generate_fastapi_boilerplate
|
|
@@ -46,6 +47,7 @@ def init_spring(
|
|
|
46
47
|
|
|
47
48
|
if success_download:
|
|
48
49
|
generate_config(name, db_type=db, custom_port=port)
|
|
50
|
+
generate_agent_context()
|
|
49
51
|
typer.secho("\nSpring project ready!", fg=typer.colors.GREEN)
|
|
50
52
|
|
|
51
53
|
|
|
@@ -61,6 +63,7 @@ def init_angular(name: str):
|
|
|
61
63
|
success = generate_angular_boilerplate(name)
|
|
62
64
|
|
|
63
65
|
if success:
|
|
66
|
+
generate_agent_context()
|
|
64
67
|
typer.secho("\nAngular project ready!", fg=typer.colors.GREEN)
|
|
65
68
|
|
|
66
69
|
|
|
@@ -75,6 +78,7 @@ def init_vue(name: str):
|
|
|
75
78
|
success = generate_vue_boilerplate(name)
|
|
76
79
|
|
|
77
80
|
if success:
|
|
81
|
+
generate_agent_context()
|
|
78
82
|
typer.secho("\nVue.js project ready!", fg=typer.colors.GREEN)
|
|
79
83
|
|
|
80
84
|
|
|
@@ -89,6 +93,7 @@ def init_nest(name: str):
|
|
|
89
93
|
success = generate_nest_boilerplate(name)
|
|
90
94
|
|
|
91
95
|
if success:
|
|
96
|
+
generate_agent_context()
|
|
92
97
|
typer.secho("\nNestJS project ready!", fg=typer.colors.GREEN)
|
|
93
98
|
|
|
94
99
|
|
|
@@ -103,6 +108,7 @@ def init_nodejs(name: str):
|
|
|
103
108
|
success = generate_nodejs_boilerplate(name)
|
|
104
109
|
|
|
105
110
|
if success:
|
|
111
|
+
generate_agent_context()
|
|
106
112
|
typer.secho("\nNodeJS project ready!", fg=typer.colors.GREEN)
|
|
107
113
|
|
|
108
114
|
|
|
@@ -117,6 +123,7 @@ def init_react(name: str):
|
|
|
117
123
|
success = generate_react_boilerplate(name)
|
|
118
124
|
|
|
119
125
|
if success:
|
|
126
|
+
generate_agent_context()
|
|
120
127
|
typer.secho("\nReactJS project ready!", fg=typer.colors.GREEN)
|
|
121
128
|
|
|
122
129
|
|
|
@@ -131,6 +138,7 @@ def init_nextjs(name: str):
|
|
|
131
138
|
success = generate_nextjs_boilerplate(name)
|
|
132
139
|
|
|
133
140
|
if success:
|
|
141
|
+
generate_agent_context()
|
|
134
142
|
typer.secho("\nNextJS project ready!", fg=typer.colors.GREEN)
|
|
135
143
|
|
|
136
144
|
|
|
@@ -145,6 +153,7 @@ def init_fastapi(name: str):
|
|
|
145
153
|
success = generate_fastapi_boilerplate(name)
|
|
146
154
|
|
|
147
155
|
if success:
|
|
156
|
+
generate_agent_context()
|
|
148
157
|
typer.secho("\nFastAPI project ready!", fg=typer.colors.GREEN)
|
|
149
158
|
|
|
150
159
|
|
|
@@ -159,6 +168,7 @@ def init_django(name: str):
|
|
|
159
168
|
success = generate_django_boilerplate(name)
|
|
160
169
|
|
|
161
170
|
if success:
|
|
171
|
+
generate_agent_context()
|
|
162
172
|
typer.secho("\nDjango project ready!", fg=typer.colors.GREEN)
|
|
163
173
|
|
|
164
174
|
|
|
@@ -173,6 +183,7 @@ def init_svelte(name: str):
|
|
|
173
183
|
success = generate_svelte_boilerplate(name)
|
|
174
184
|
|
|
175
185
|
if success:
|
|
186
|
+
generate_agent_context()
|
|
176
187
|
typer.secho("\nSvelte project ready!", fg=typer.colors.GREEN)
|
|
177
188
|
|
|
178
189
|
|
|
@@ -187,4 +198,18 @@ def init_go(name: str):
|
|
|
187
198
|
success = generate_go_boilerplate(name)
|
|
188
199
|
|
|
189
200
|
if success:
|
|
201
|
+
generate_agent_context()
|
|
190
202
|
typer.secho("\nGo project ready!", fg=typer.colors.GREEN)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@app.command("agent")
|
|
206
|
+
def init_agent():
|
|
207
|
+
"""
|
|
208
|
+
Generates or refreshes AGENTS.md, CLAUDE.md, and .cursorrules for the current project.
|
|
209
|
+
"""
|
|
210
|
+
success = generate_agent_context()
|
|
211
|
+
if success:
|
|
212
|
+
typer.secho("\nAgent context ready!", fg=typer.colors.GREEN)
|
|
213
|
+
else:
|
|
214
|
+
typer.secho("\nFailed to generate agent context.", fg=typer.colors.RED)
|
|
215
|
+
raise typer.Exit(code=1)
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent context generator.
|
|
3
|
+
Produces AGENTS.md, CLAUDE.md, and .cursorrules for AI coding assistants.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import re
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict, List, Union
|
|
12
|
+
|
|
13
|
+
import typer
|
|
14
|
+
import yaml
|
|
15
|
+
from jinja2 import Environment, FileSystemLoader
|
|
16
|
+
|
|
17
|
+
from devctl.generators.docker.scaffolder import IGNORED_DIRECTORIES, discover_docker_projects
|
|
18
|
+
|
|
19
|
+
FRAMEWORK_METADATA: Dict[str, Dict[str, Any]] = {
|
|
20
|
+
"spring": {
|
|
21
|
+
"framework": "Spring Boot",
|
|
22
|
+
"category": "backend",
|
|
23
|
+
"default_port": 8080,
|
|
24
|
+
"run_cmd": "./mvnw spring-boot:run",
|
|
25
|
+
"test_cmd": "./mvnw test",
|
|
26
|
+
},
|
|
27
|
+
"fastapi": {
|
|
28
|
+
"framework": "FastAPI",
|
|
29
|
+
"category": "backend",
|
|
30
|
+
"default_port": 8000,
|
|
31
|
+
"run_cmd": "uvicorn main:app --reload",
|
|
32
|
+
"test_cmd": "pytest",
|
|
33
|
+
},
|
|
34
|
+
"django": {
|
|
35
|
+
"framework": "Django",
|
|
36
|
+
"category": "backend",
|
|
37
|
+
"default_port": 8000,
|
|
38
|
+
"run_cmd": "python manage.py runserver",
|
|
39
|
+
"test_cmd": "python manage.py test",
|
|
40
|
+
},
|
|
41
|
+
"nest": {
|
|
42
|
+
"framework": "NestJS",
|
|
43
|
+
"category": "backend",
|
|
44
|
+
"default_port": 3000,
|
|
45
|
+
"run_cmd": "npm run start:dev",
|
|
46
|
+
"test_cmd": "npm test",
|
|
47
|
+
},
|
|
48
|
+
"nodejs": {
|
|
49
|
+
"framework": "NodeJS / Express",
|
|
50
|
+
"category": "backend",
|
|
51
|
+
"default_port": 3000,
|
|
52
|
+
"run_cmd": "npm run dev",
|
|
53
|
+
"test_cmd": "npm test",
|
|
54
|
+
},
|
|
55
|
+
"go": {
|
|
56
|
+
"framework": "Go (Fiber)",
|
|
57
|
+
"category": "backend",
|
|
58
|
+
"default_port": 3000,
|
|
59
|
+
"run_cmd": "go run .",
|
|
60
|
+
"test_cmd": "go test ./...",
|
|
61
|
+
},
|
|
62
|
+
"angular": {
|
|
63
|
+
"framework": "Angular",
|
|
64
|
+
"category": "frontend",
|
|
65
|
+
"default_port": 4200,
|
|
66
|
+
"run_cmd": "npx ng serve",
|
|
67
|
+
"test_cmd": "npm test",
|
|
68
|
+
},
|
|
69
|
+
"vue": {
|
|
70
|
+
"framework": "Vue 3",
|
|
71
|
+
"category": "frontend",
|
|
72
|
+
"default_port": 5173,
|
|
73
|
+
"run_cmd": "npm run dev",
|
|
74
|
+
"test_cmd": "npm test",
|
|
75
|
+
},
|
|
76
|
+
"react": {
|
|
77
|
+
"framework": "React",
|
|
78
|
+
"category": "frontend",
|
|
79
|
+
"default_port": 5173,
|
|
80
|
+
"run_cmd": "npm run dev",
|
|
81
|
+
"test_cmd": "npm test",
|
|
82
|
+
},
|
|
83
|
+
"nextjs": {
|
|
84
|
+
"framework": "Next.js",
|
|
85
|
+
"category": "frontend",
|
|
86
|
+
"default_port": 3000,
|
|
87
|
+
"run_cmd": "npm run dev",
|
|
88
|
+
"test_cmd": "npm test",
|
|
89
|
+
},
|
|
90
|
+
"svelte": {
|
|
91
|
+
"framework": "Svelte",
|
|
92
|
+
"category": "frontend",
|
|
93
|
+
"default_port": 5173,
|
|
94
|
+
"run_cmd": "npm run dev",
|
|
95
|
+
"test_cmd": "npm test",
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _detect_service_port(project_path: Path, kind: str, default_port: int) -> int:
|
|
101
|
+
"""Extract configured service port or fallback to default."""
|
|
102
|
+
if kind == "spring":
|
|
103
|
+
props_path = project_path / "src" / "main" / "resources" / "application.properties"
|
|
104
|
+
if props_path.exists():
|
|
105
|
+
try:
|
|
106
|
+
content = props_path.read_text(encoding="utf-8")
|
|
107
|
+
match = re.search(r"^server\.port\s*=\s*(\d+)", content, re.MULTILINE)
|
|
108
|
+
if match:
|
|
109
|
+
return int(match.group(1))
|
|
110
|
+
except Exception:
|
|
111
|
+
pass
|
|
112
|
+
return default_port
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _discover_databases(root: Path) -> List[Dict[str, Any]]:
|
|
116
|
+
"""Scan for docker-compose-db.yml files and extract service configuration."""
|
|
117
|
+
databases: List[Dict[str, Any]] = []
|
|
118
|
+
|
|
119
|
+
for dirpath, dirnames, filenames in os.walk(root):
|
|
120
|
+
dirnames[:] = [d for d in dirnames if d not in IGNORED_DIRECTORIES]
|
|
121
|
+
if "docker-compose-db.yml" in filenames:
|
|
122
|
+
compose_path = Path(dirpath) / "docker-compose-db.yml"
|
|
123
|
+
try:
|
|
124
|
+
content = yaml.safe_load(compose_path.read_text(encoding="utf-8")) or {}
|
|
125
|
+
services = content.get("services", {})
|
|
126
|
+
for s_name, s_conf in services.items():
|
|
127
|
+
image = str(s_conf.get("image", "unknown"))
|
|
128
|
+
ports = s_conf.get("ports", [])
|
|
129
|
+
host_port = "unknown"
|
|
130
|
+
if ports:
|
|
131
|
+
raw_port = str(ports[0])
|
|
132
|
+
host_port = raw_port.split(":")[0] if ":" in raw_port else raw_port
|
|
133
|
+
|
|
134
|
+
env_vars = s_conf.get("environment", {})
|
|
135
|
+
if isinstance(env_vars, list):
|
|
136
|
+
parsed_env = {}
|
|
137
|
+
for item in env_vars:
|
|
138
|
+
if isinstance(item, str) and "=" in item:
|
|
139
|
+
k, v = item.split("=", 1)
|
|
140
|
+
parsed_env[k.strip()] = v.strip()
|
|
141
|
+
env_vars = parsed_env
|
|
142
|
+
|
|
143
|
+
db_user = (
|
|
144
|
+
env_vars.get("POSTGRES_USER")
|
|
145
|
+
or env_vars.get("MYSQL_USER")
|
|
146
|
+
or env_vars.get("MONGO_INITDB_ROOT_USERNAME")
|
|
147
|
+
or "admin"
|
|
148
|
+
)
|
|
149
|
+
db_password = (
|
|
150
|
+
env_vars.get("POSTGRES_PASSWORD")
|
|
151
|
+
or env_vars.get("MYSQL_PASSWORD")
|
|
152
|
+
or env_vars.get("MONGO_INITDB_ROOT_PASSWORD")
|
|
153
|
+
or "password"
|
|
154
|
+
)
|
|
155
|
+
db_name = (
|
|
156
|
+
env_vars.get("POSTGRES_DB")
|
|
157
|
+
or env_vars.get("MYSQL_DATABASE")
|
|
158
|
+
or env_vars.get("MONGO_INITDB_DATABASE")
|
|
159
|
+
or "default_db"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
image_lower = image.lower()
|
|
163
|
+
if "postgres" in image_lower:
|
|
164
|
+
db_type = "PostgreSQL"
|
|
165
|
+
elif "mysql" in image_lower:
|
|
166
|
+
db_type = "MySQL"
|
|
167
|
+
elif "mongo" in image_lower:
|
|
168
|
+
db_type = "MongoDB"
|
|
169
|
+
else:
|
|
170
|
+
db_type = "Database"
|
|
171
|
+
|
|
172
|
+
rel_compose = compose_path.relative_to(root).as_posix()
|
|
173
|
+
databases.append(
|
|
174
|
+
{
|
|
175
|
+
"service_name": s_name,
|
|
176
|
+
"db_type": db_type,
|
|
177
|
+
"image": image,
|
|
178
|
+
"port": host_port,
|
|
179
|
+
"db_name": db_name,
|
|
180
|
+
"db_user": db_user,
|
|
181
|
+
"db_password": db_password,
|
|
182
|
+
"compose_file": f"./{rel_compose}",
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
except Exception:
|
|
186
|
+
pass
|
|
187
|
+
|
|
188
|
+
return databases
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def generate_agent_context(root_path: Union[str, Path] = ".") -> bool:
|
|
192
|
+
"""
|
|
193
|
+
Scans the repository and generates AGENTS.md, CLAUDE.md, and .cursorrules.
|
|
194
|
+
"""
|
|
195
|
+
root = Path(root_path).resolve()
|
|
196
|
+
if not root.exists() or not root.is_dir():
|
|
197
|
+
return False
|
|
198
|
+
|
|
199
|
+
try:
|
|
200
|
+
discovered = discover_docker_projects(root)
|
|
201
|
+
except Exception:
|
|
202
|
+
discovered = []
|
|
203
|
+
|
|
204
|
+
services: List[Dict[str, Any]] = []
|
|
205
|
+
backends: List[Dict[str, Any]] = []
|
|
206
|
+
frontends: List[Dict[str, Any]] = []
|
|
207
|
+
|
|
208
|
+
for p in discovered:
|
|
209
|
+
meta = FRAMEWORK_METADATA.get(
|
|
210
|
+
p.kind,
|
|
211
|
+
{
|
|
212
|
+
"framework": p.kind.capitalize(),
|
|
213
|
+
"category": "backend",
|
|
214
|
+
"default_port": 8080,
|
|
215
|
+
"run_cmd": "devctl run",
|
|
216
|
+
"test_cmd": "npm test",
|
|
217
|
+
},
|
|
218
|
+
)
|
|
219
|
+
port = _detect_service_port(p.path, p.kind, meta["default_port"])
|
|
220
|
+
try:
|
|
221
|
+
rel_path = f"./{p.path.relative_to(root).as_posix()}"
|
|
222
|
+
except ValueError:
|
|
223
|
+
rel_path = f"./{p.name}"
|
|
224
|
+
|
|
225
|
+
service_data = {
|
|
226
|
+
"name": p.name,
|
|
227
|
+
"kind": p.kind,
|
|
228
|
+
"framework": meta["framework"],
|
|
229
|
+
"category": meta["category"],
|
|
230
|
+
"relative_path": rel_path,
|
|
231
|
+
"port": port,
|
|
232
|
+
"run_cmd": meta["run_cmd"],
|
|
233
|
+
"test_cmd": meta["test_cmd"],
|
|
234
|
+
}
|
|
235
|
+
services.append(service_data)
|
|
236
|
+
if meta["category"] == "backend":
|
|
237
|
+
backends.append(service_data)
|
|
238
|
+
else:
|
|
239
|
+
frontends.append(service_data)
|
|
240
|
+
|
|
241
|
+
databases = _discover_databases(root)
|
|
242
|
+
|
|
243
|
+
template_dir = Path(__file__).parent / "templates"
|
|
244
|
+
env = Environment(loader=FileSystemLoader(str(template_dir)), autoescape=False)
|
|
245
|
+
|
|
246
|
+
context = {
|
|
247
|
+
"services": services,
|
|
248
|
+
"backends": backends,
|
|
249
|
+
"frontends": frontends,
|
|
250
|
+
"databases": databases,
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
agents_tpl = env.get_template("AGENTS.md.j2")
|
|
255
|
+
claude_tpl = env.get_template("CLAUDE.md.j2")
|
|
256
|
+
cursor_tpl = env.get_template(".cursorrules.j2")
|
|
257
|
+
|
|
258
|
+
(root / "AGENTS.md").write_text(agents_tpl.render(context), encoding="utf-8")
|
|
259
|
+
(root / "CLAUDE.md").write_text(claude_tpl.render(context), encoding="utf-8")
|
|
260
|
+
(root / ".cursorrules").write_text(cursor_tpl.render(context), encoding="utf-8")
|
|
261
|
+
|
|
262
|
+
typer.secho(
|
|
263
|
+
"Agent context generated (AGENTS.md, CLAUDE.md, .cursorrules).",
|
|
264
|
+
fg=typer.colors.CYAN,
|
|
265
|
+
)
|
|
266
|
+
return True
|
|
267
|
+
except Exception as e:
|
|
268
|
+
typer.secho(f"Warning: Failed to generate agent context: {e}", fg=typer.colors.YELLOW)
|
|
269
|
+
return False
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Project Development Guide for AI Agents
|
|
2
|
+
|
|
3
|
+
> This project is orchestrated using `devctl`. All commands, multi-tier processes,
|
|
4
|
+
> and scaffolding workflows must adhere to the boundaries documented below.
|
|
5
|
+
|
|
6
|
+
## 1. Project Architecture & Active Topology
|
|
7
|
+
{% if backends %}
|
|
8
|
+
### Backend Services
|
|
9
|
+
{% for b in backends %}
|
|
10
|
+
- **{{ b.name }}** ({{ b.framework }})
|
|
11
|
+
- Path: `{{ b.relative_path }}`
|
|
12
|
+
- Local Port: `{{ b.port }}`
|
|
13
|
+
- Run Command: `{{ b.run_cmd }}`
|
|
14
|
+
- Test Suite: `{{ b.test_cmd }}`
|
|
15
|
+
{% endfor %}
|
|
16
|
+
{% endif %}
|
|
17
|
+
{% if frontends %}
|
|
18
|
+
### Frontend Services
|
|
19
|
+
{% for f in frontends %}
|
|
20
|
+
- **{{ f.name }}** ({{ f.framework }})
|
|
21
|
+
- Path: `{{ f.relative_path }}`
|
|
22
|
+
- Local Dev Port: `{{ f.port }}`
|
|
23
|
+
- Run Command: `{{ f.run_cmd }}`
|
|
24
|
+
- Test Suite: `{{ f.test_cmd }}`
|
|
25
|
+
{% endfor %}
|
|
26
|
+
{% endif %}
|
|
27
|
+
{% if databases %}
|
|
28
|
+
### Databases & Infrastructure
|
|
29
|
+
{% for db in databases %}
|
|
30
|
+
- **Service**: `{{ db.service_name }}`
|
|
31
|
+
- Type: `{{ db.db_type }}`
|
|
32
|
+
- Image: `{{ db.image }}`
|
|
33
|
+
- Host Port: `{{ db.port }}`
|
|
34
|
+
- Database Name: `{{ db.db_name }}`
|
|
35
|
+
- Credentials: User=`{{ db.db_user }}`, Password=`{{ db.db_password }}`
|
|
36
|
+
- Compose File: `{{ db.compose_file }}`
|
|
37
|
+
{% endfor %}
|
|
38
|
+
{% endif %}
|
|
39
|
+
{% if not backends and not frontends and not databases %}
|
|
40
|
+
- Topology: No active microservices detected yet. Run `devctl init <framework> <name>` to add services.
|
|
41
|
+
{% endif %}
|
|
42
|
+
|
|
43
|
+
## 2. Devctl Orchestration & Lifecycle Commands
|
|
44
|
+
|
|
45
|
+
Always use `devctl` to orchestrate services. Do NOT start background daemons, manually detached docker processes, or raw ad-hoc runners unless debugging an isolated failure.
|
|
46
|
+
|
|
47
|
+
- **Start entire stack** (Databases + Backends + Frontends in parallel with unified log streaming):
|
|
48
|
+
```bash
|
|
49
|
+
devctl run
|
|
50
|
+
```
|
|
51
|
+
- **Interactive TUI Dashboard** (System metrics, real-time log inspection, process management):
|
|
52
|
+
```bash
|
|
53
|
+
devctl tui
|
|
54
|
+
```
|
|
55
|
+
- **Vertical Full-Stack Scaffolding** (Generates Entity, DTOs, Repository, Service, Controller, and Frontend client):
|
|
56
|
+
```bash
|
|
57
|
+
devctl add resource <ResourceName> -f "<field1>:<type>,<field2>:<type>"
|
|
58
|
+
```
|
|
59
|
+
- **Containerization & Deployment Scaffolding**:
|
|
60
|
+
```bash
|
|
61
|
+
devctl docker scaffold
|
|
62
|
+
devctl docker generate
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 3. Full-Stack Contract & Coding Conventions
|
|
66
|
+
|
|
67
|
+
When adding or modifying API endpoints or data models:
|
|
68
|
+
- **API Endpoints**: Use standard RESTful patterns with `/api/v1` prefixes.
|
|
69
|
+
- **DTOs / Contracts**:
|
|
70
|
+
- Request payloads must be modeled with `<Entity>Request` DTOs.
|
|
71
|
+
- Response payloads must be modeled with `<Entity>Response` DTOs.
|
|
72
|
+
- **Type Compatibility**:
|
|
73
|
+
- Backend numeric IDs / Long / Integer -> Frontend TypeScript `number`
|
|
74
|
+
- Backend UUID / String -> Frontend TypeScript `string`
|
|
75
|
+
- Backend Instant / LocalDateTime / DateTime -> Frontend TypeScript `string` (ISO 8601 formatted)
|
|
76
|
+
- Backend Boolean -> Frontend TypeScript `boolean`
|
|
77
|
+
- **Synchronization**: Any change to backend DTO fields or endpoints MUST be immediately reflected in the corresponding frontend API client, models, and interfaces.
|
|
78
|
+
|
|
79
|
+
## 4. Agent Operational Guardrails
|
|
80
|
+
|
|
81
|
+
- **Process Management**: Do NOT run detached background processes (`nohup`, `&`, `screen`, `tmux`) that outlive the session. Use `devctl run` for execution.
|
|
82
|
+
- **Testing Before Completion**: Always run the respective test suite for modified services before concluding any task:
|
|
83
|
+
{% for s in services %}
|
|
84
|
+
- `{{ s.name }}`: `{{ s.test_cmd }}`
|
|
85
|
+
{% endfor %}
|
|
86
|
+
- **Docker Compose Boundaries**: Do NOT alter database port mappings in `docker-compose-db.yml` without updating application configuration files in lockstep.
|
|
87
|
+
- **Dependency Checks**: Ensure required tools are available using `devctl` verification conventions before executing framework-specific build scripts.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Claude Code Guidelines
|
|
2
|
+
|
|
3
|
+
This project is managed and orchestrated by `devctl`.
|
|
4
|
+
|
|
5
|
+
- Review [AGENTS.md](AGENTS.md) for complete architecture topology, active services, port allocations, and devctl lifecycle commands.
|
|
6
|
+
- Use `devctl run` to boot services and `devctl add resource` for full-stack CRUD scaffolding.
|
|
7
|
+
- Ensure backend DTOs and frontend TypeScript interfaces remain strictly synchronized.
|
|
8
|
+
- Execute unit and integration tests before finishing tasks.
|
|
@@ -55,6 +55,7 @@ from devctl.commands.init import (
|
|
|
55
55
|
generate_svelte_boilerplate,
|
|
56
56
|
generate_vue_boilerplate,
|
|
57
57
|
)
|
|
58
|
+
from devctl.generators.agent import generate_agent_context
|
|
58
59
|
from devctl.generators.docker import discover_docker_projects, scaffold_docker_assets
|
|
59
60
|
from devctl.orchestrator.config_builder import generate_config
|
|
60
61
|
from devctl.orchestrator.process_manager import ProcessManager
|
|
@@ -789,6 +790,7 @@ class DevctlTUI(App):
|
|
|
789
790
|
generate_go_boilerplate(name)
|
|
790
791
|
else:
|
|
791
792
|
print(f"Error: Unknown framework boilerplate '{framework}'")
|
|
793
|
+
generate_agent_context(".")
|
|
792
794
|
print("\nProject initialized successfully!")
|
|
793
795
|
except Exception as e:
|
|
794
796
|
print(f"Error during initialization: {e}", file=f)
|