devhive 0.1.23__tar.gz → 0.1.25__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 (52) hide show
  1. {devhive-0.1.23 → devhive-0.1.25}/MANIFEST.in +2 -0
  2. {devhive-0.1.23/devhive.egg-info → devhive-0.1.25}/PKG-INFO +8 -2
  3. {devhive-0.1.23 → devhive-0.1.25}/README.md +6 -0
  4. {devhive-0.1.23 → devhive-0.1.25/devhive.egg-info}/PKG-INFO +8 -2
  5. {devhive-0.1.23 → devhive-0.1.25}/devhive.egg-info/SOURCES.txt +3 -1
  6. {devhive-0.1.23 → devhive-0.1.25}/devhive_cli/main.py +47 -0
  7. devhive-0.1.25/devhive_cli/templates_backend.py +424 -0
  8. {devhive-0.1.23 → devhive-0.1.25}/setup.py +2 -2
  9. devhive-0.1.25/templates/AGENTS.frontend.md +160 -0
  10. {devhive-0.1.23 → devhive-0.1.25}/LICENSE +0 -0
  11. {devhive-0.1.23 → devhive-0.1.25}/community_skills/architecture-patterns/SKILL.md +0 -0
  12. {devhive-0.1.23 → devhive-0.1.25}/community_skills/architecture-patterns/resources/implementation-playbook.md +0 -0
  13. {devhive-0.1.23 → devhive-0.1.25}/community_skills/backend-arthitect/SKILL.md +0 -0
  14. {devhive-0.1.23 → devhive-0.1.25}/community_skills/backend-security-coder/SKILL.md +0 -0
  15. {devhive-0.1.23 → devhive-0.1.25}/community_skills/docker-expert/SKILL.md +0 -0
  16. {devhive-0.1.23 → devhive-0.1.25}/community_skills/frontend-design/SKILL.md +0 -0
  17. {devhive-0.1.23 → devhive-0.1.25}/community_skills/frontend-developer/SKILL.md +0 -0
  18. {devhive-0.1.23 → devhive-0.1.25}/community_skills/theme-factory/SKILL.md +0 -0
  19. {devhive-0.1.23 → devhive-0.1.25}/community_skills/theme-factory/theme-showcase.pdf +0 -0
  20. {devhive-0.1.23 → devhive-0.1.25}/community_skills/theme-factory/themes/arctic-frost.md +0 -0
  21. {devhive-0.1.23 → devhive-0.1.25}/community_skills/theme-factory/themes/botanical-garden.md +0 -0
  22. {devhive-0.1.23 → devhive-0.1.25}/community_skills/theme-factory/themes/desert-rose.md +0 -0
  23. {devhive-0.1.23 → devhive-0.1.25}/community_skills/theme-factory/themes/forest-canopy.md +0 -0
  24. {devhive-0.1.23 → devhive-0.1.25}/community_skills/theme-factory/themes/golden-hour.md +0 -0
  25. {devhive-0.1.23 → devhive-0.1.25}/community_skills/theme-factory/themes/midnight-galaxy.md +0 -0
  26. {devhive-0.1.23 → devhive-0.1.25}/community_skills/theme-factory/themes/modern-minimalist.md +0 -0
  27. {devhive-0.1.23 → devhive-0.1.25}/community_skills/theme-factory/themes/ocean-depths.md +0 -0
  28. {devhive-0.1.23 → devhive-0.1.25}/community_skills/theme-factory/themes/sunset-boulevard.md +0 -0
  29. {devhive-0.1.23 → devhive-0.1.25}/community_skills/theme-factory/themes/tech-innovation.md +0 -0
  30. {devhive-0.1.23 → devhive-0.1.25}/devhive.egg-info/dependency_links.txt +0 -0
  31. {devhive-0.1.23 → devhive-0.1.25}/devhive.egg-info/entry_points.txt +0 -0
  32. {devhive-0.1.23 → devhive-0.1.25}/devhive.egg-info/requires.txt +0 -0
  33. {devhive-0.1.23 → devhive-0.1.25}/devhive.egg-info/top_level.txt +0 -0
  34. {devhive-0.1.23 → devhive-0.1.25}/devhive_cli/__init__.py +0 -0
  35. {devhive-0.1.23 → devhive-0.1.25}/setup.cfg +0 -0
  36. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_architect/SKILL.md +0 -0
  37. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_auditor/SKILL.md +0 -0
  38. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_backender/SKILL.md +0 -0
  39. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_dba/SKILL.md +0 -0
  40. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_designer/SKILL.md +0 -0
  41. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_devops/SKILL.md +0 -0
  42. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_explorer/SKILL.md +0 -0
  43. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_frontender/SKILL.md +0 -0
  44. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_orchestrator/SKILL.md +0 -0
  45. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_perf/SKILL.md +0 -0
  46. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_proposal/SKILL.md +0 -0
  47. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_qa/SKILL.md +0 -0
  48. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_releaser/SKILL.md +0 -0
  49. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_sast/SKILL.md +0 -0
  50. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_taskplanner/SKILL.md +0 -0
  51. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_techwriter/SKILL.md +0 -0
  52. {devhive-0.1.23 → devhive-0.1.25}/skills/devhive_workflow.md +0 -0
@@ -1,2 +1,4 @@
1
1
  recursive-include skills *
2
2
  recursive-include community_skills *
3
+ recursive-include templates *
4
+
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devhive
3
- Version: 0.1.23
3
+ Version: 0.1.25
4
4
  Summary: CLI to manage DevHive skills and autonomous AI agents for OpenCode.
5
5
  Home-page: https://github.com/ramBlanco/devhive
6
6
  Author: ramBlanco
7
7
  Classifier: Programming Language :: Python :: 3
8
8
  Classifier: License :: OSI Approved :: MIT License
9
9
  Classifier: Operating System :: OS Independent
10
- Requires-Python: >=3.8
10
+ Requires-Python: >=3.7
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
13
  Requires-Dist: click>=8.0.0
@@ -65,6 +65,12 @@ devhive install
65
65
 
66
66
  # Update your existing skills to the latest versions
67
67
  devhive update-skill
68
+
69
+ # Initialize a modern Next.js/React frontend AI guidelines file in your current project
70
+ devhive init-frontend
71
+
72
+ # Initialize a Hexagonal Architecture backend AI guidelines file (Interactive Prompt)
73
+ devhive init-backend
68
74
  ```
69
75
 
70
76
  ## Usage (The `@devhive` Agent)
@@ -42,6 +42,12 @@ devhive install
42
42
 
43
43
  # Update your existing skills to the latest versions
44
44
  devhive update-skill
45
+
46
+ # Initialize a modern Next.js/React frontend AI guidelines file in your current project
47
+ devhive init-frontend
48
+
49
+ # Initialize a Hexagonal Architecture backend AI guidelines file (Interactive Prompt)
50
+ devhive init-backend
45
51
  ```
46
52
 
47
53
  ## Usage (The `@devhive` Agent)
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devhive
3
- Version: 0.1.23
3
+ Version: 0.1.25
4
4
  Summary: CLI to manage DevHive skills and autonomous AI agents for OpenCode.
5
5
  Home-page: https://github.com/ramBlanco/devhive
6
6
  Author: ramBlanco
7
7
  Classifier: Programming Language :: Python :: 3
8
8
  Classifier: License :: OSI Approved :: MIT License
9
9
  Classifier: Operating System :: OS Independent
10
- Requires-Python: >=3.8
10
+ Requires-Python: >=3.7
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
13
  Requires-Dist: click>=8.0.0
@@ -65,6 +65,12 @@ devhive install
65
65
 
66
66
  # Update your existing skills to the latest versions
67
67
  devhive update-skill
68
+
69
+ # Initialize a modern Next.js/React frontend AI guidelines file in your current project
70
+ devhive init-frontend
71
+
72
+ # Initialize a Hexagonal Architecture backend AI guidelines file (Interactive Prompt)
73
+ devhive init-backend
68
74
  ```
69
75
 
70
76
  ## Usage (The `@devhive` Agent)
@@ -29,6 +29,7 @@ devhive.egg-info/requires.txt
29
29
  devhive.egg-info/top_level.txt
30
30
  devhive_cli/__init__.py
31
31
  devhive_cli/main.py
32
+ devhive_cli/templates_backend.py
32
33
  skills/devhive_workflow.md
33
34
  skills/devhive_architect/SKILL.md
34
35
  skills/devhive_auditor/SKILL.md
@@ -45,4 +46,5 @@ skills/devhive_qa/SKILL.md
45
46
  skills/devhive_releaser/SKILL.md
46
47
  skills/devhive_sast/SKILL.md
47
48
  skills/devhive_taskplanner/SKILL.md
48
- skills/devhive_techwriter/SKILL.md
49
+ skills/devhive_techwriter/SKILL.md
50
+ templates/AGENTS.frontend.md
@@ -3,12 +3,14 @@ import shutil
3
3
  import subprocess
4
4
  from pathlib import Path
5
5
  import click
6
+ from devhive_cli.templates_backend import generate_backend_agents_md
6
7
 
7
8
  # Paths configuration
8
9
  CLI_DIR = Path(__file__).resolve().parent
9
10
  ROOT_DIR = CLI_DIR.parent
10
11
  LOCAL_SKILLS_DIR = ROOT_DIR / "skills"
11
12
  COMMUNITY_SKILLS_DIR = ROOT_DIR / "community_skills"
13
+ TEMPLATES_DIR = ROOT_DIR / "templates"
12
14
  TARGET_DIR = Path.home() / ".config" / "opencode" / "skills"
13
15
 
14
16
  @click.group()
@@ -75,5 +77,50 @@ def update_skill():
75
77
  install_remote_skills()
76
78
  click.secho("\nUpdate Complete! 🚀", fg="green", bold=True)
77
79
 
80
+ @cli.command()
81
+ def init_frontend():
82
+ """Initialize a modern frontend AGENTS.md template in the current directory."""
83
+ template_path = TEMPLATES_DIR / "AGENTS.frontend.md"
84
+ dest_path = Path.cwd() / "AGENTS.md"
85
+
86
+ if not template_path.exists():
87
+ click.secho("Error: Frontend template not found in the devhive package.", fg="red")
88
+ return
89
+
90
+ if dest_path.exists():
91
+ click.secho("AGENTS.md already exists in this directory. Aborting to prevent overwrite.", fg="yellow")
92
+ return
93
+
94
+ shutil.copy2(template_path, dest_path)
95
+ click.secho("✅ Successfully created AGENTS.md with modern Next.js/React frontend guidelines!", fg="green", bold=True)
96
+
97
+ @cli.command()
98
+ def init_backend():
99
+ """Initialize a modern backend AGENTS.md template with Hexagonal Architecture."""
100
+ dest_path = Path.cwd() / "AGENTS.md"
101
+
102
+ if dest_path.exists():
103
+ click.secho("AGENTS.md already exists in this directory. Aborting to prevent overwrite.", fg="yellow")
104
+ return
105
+
106
+ language = click.prompt("Which backend language?", type=click.Choice(['python', 'node']))
107
+
108
+ use_di = False
109
+ if language == 'python':
110
+ framework = click.prompt("Which framework?", type=click.Choice(['fastapi', 'django', 'none']))
111
+ else:
112
+ framework = click.prompt("Which framework?", type=click.Choice(['express', 'nestjs', 'none']))
113
+ if framework != 'nestjs':
114
+ use_di = click.confirm("Do you want to use InversifyJS for Dependency Injection?")
115
+
116
+ iac = click.prompt("Which IaC tool are you using?", type=click.Choice(['cdk', 'terraform', 'serverless']))
117
+
118
+ md_content = generate_backend_agents_md(language, framework, iac, use_di)
119
+
120
+ with open(dest_path, "w", encoding="utf-8") as f:
121
+ f.write(md_content)
122
+
123
+ click.secho("✅ Successfully created AGENTS.md with Hexagonal Architecture guidelines!", fg="green", bold=True)
124
+
78
125
  if __name__ == "__main__":
79
126
  cli()
@@ -0,0 +1,424 @@
1
+ def generate_backend_agents_md(language: str, framework: str, iac: str, use_di: bool) -> str:
2
+ stack_list = []
3
+ if language == 'python':
4
+ stack_list.append("- **Language**: Python 3.10+ (Strict Type Hinting)")
5
+ if framework == 'fastapi':
6
+ stack_list.append("- **Framework**: FastAPI")
7
+ elif framework == 'django':
8
+ stack_list.append("- **Framework**: Django")
9
+ else:
10
+ stack_list.append("- **Framework**: None (Pure Python / Lambdas)")
11
+ else:
12
+ stack_list.append("- **Language**: Node.js + TypeScript (Strict Mode)")
13
+ if framework == 'express':
14
+ stack_list.append("- **Framework**: Express")
15
+ elif framework == 'nestjs':
16
+ stack_list.append("- **Framework**: NestJS (Built-in DI)")
17
+ use_di = False # NestJS has its own DI
18
+ else:
19
+ stack_list.append("- **Framework**: None (Pure Node.js / Lambdas)")
20
+
21
+ if use_di:
22
+ stack_list.append("- **Dependency Injection**: InversifyJS")
23
+
24
+ if iac == 'cdk':
25
+ stack_list.append("- **Infrastructure as Code**: AWS CDK")
26
+ elif iac == 'terraform':
27
+ stack_list.append("- **Infrastructure as Code**: Terraform")
28
+ else:
29
+ stack_list.append("- **Infrastructure as Code**: Serverless Framework")
30
+
31
+ stack_section = "\n".join(stack_list)
32
+
33
+ # Base structure
34
+ md = f"""# Backend Architecture & AI Agent Guidelines
35
+
36
+ This `AGENTS.md` (or `GUIDELINES.md`) file serves as the strict instruction manual for OpenCode and DevHive agents. It defines the technical stack, architectural patterns, and coding conventions for this backend project.
37
+
38
+ ## 🛠️ 1. Tech Stack
39
+ {stack_section}
40
+
41
+ ## 🧠 2. OpenCode Skills to Load
42
+ Agents **MUST** load the following specialized skills before executing tasks:
43
+ - `architecture-patterns`: For maintaining clean separation of concerns and Hexagonal Architecture.
44
+ - `backend-architect`: For scalable API design and domain modeling.
45
+ - `backend-security-coder`: For secure coding practices, input validation, and auth.
46
+ - `devhive-devops`: For {iac.upper()} infrastructure setup.
47
+
48
+ ## 📂 3. Project Structure (Hexagonal Architecture)
49
+ For maximum scalability, testability, and maintainability, the project MUST strictly follow Hexagonal Architecture (Ports & Adapters).
50
+
51
+ ```text
52
+ src/
53
+ ├── domain/ # ENTERPRISE BUSINESS RULES (No external dependencies)
54
+ │ ├── entities/ # Pure domain models
55
+ │ └── exceptions/ # Domain-specific errors
56
+ ├── application/ # APPLICATION BUSINESS RULES (Use Cases & Ports)
57
+ │ ├── use_cases/ # Orchestrates domain logic
58
+ │ └── ports/ # Interfaces for outbound communication (Repositories, External APIs)
59
+ ├── infrastructure/ # ADAPTERS (Database, External Services, Third-party libs)
60
+ │ ├── database/ # Concrete implementation of repository ports
61
+ │ └── di/ # Dependency Injection container/setup
62
+ └── presentation/ # ENTRY POINTS (Controllers, REST APIs, GraphQL, Lambdas)
63
+ └── controllers/ # Parses HTTP requests and calls use cases
64
+
65
+ infrastructure/ # IaC DEFINITIONS (Outside src/)
66
+ └── # {iac.upper()} configurations
67
+ ```
68
+
69
+ ## 📐 4. Architectural Rules & Clean Code (CRITICAL)
70
+
71
+ 1. **The Dependency Rule**: Source code dependencies MUST only point inward, toward the `domain/`.
72
+ - `domain/` knows nothing about anything else.
73
+ - `application/` depends only on `domain/`.
74
+ - `infrastructure/` and `presentation/` depend on `application/` and `domain/`.
75
+ - **Never import an infrastructure detail (like a DB model) into a use case.**
76
+
77
+ 2. **Ports and Adapters**:
78
+ - Outbound communication (like DB queries) MUST be defined as an interface (Port) in the `application/` layer.
79
+ - The actual database logic MUST be implemented as an Adapter in the `infrastructure/` layer.
80
+
81
+ 3. **Dependency Injection**:
82
+ - Use Cases must receive their dependencies (Ports) via constructor injection.
83
+ - The Presentation layer resolves these dependencies and passes them to the Use Cases.
84
+ """
85
+
86
+ if language == 'node' and use_di:
87
+ md += """
88
+ 4. **InversifyJS Usage**:
89
+ - Decorate concrete adapters in `infrastructure/` with `@injectable()`.
90
+ - Bind interfaces to symbols in an `inversify.config.ts` container file.
91
+ - Use the container in the `presentation/` layer to resolve use cases.
92
+ """
93
+
94
+ md += "\n## 💻 5. Code Examples\n\n"
95
+
96
+ if language == 'python':
97
+ if framework == 'fastapi':
98
+ md += """### Example: FastAPI + Hexagonal Architecture
99
+
100
+ **1. Port (Application Layer)**
101
+ *File: `src/application/ports/user_repository.py`*
102
+ ```python
103
+ from typing import Protocol
104
+ from src.domain.entities.user import User
105
+
106
+ class UserRepository(Protocol):
107
+ def get_by_id(self, user_id: str) -> User | None:
108
+ ...
109
+ ```
110
+
111
+ **2. Adapter (Infrastructure Layer)**
112
+ *File: `src/infrastructure/database/postgres_user_repository.py`*
113
+ ```python
114
+ from src.application.ports.user_repository import UserRepository
115
+ from src.domain.entities.user import User
116
+
117
+ class PostgresUserRepository:
118
+ def __init__(self, db_session):
119
+ self.db = db_session
120
+
121
+ def get_by_id(self, user_id: str) -> User | None:
122
+ # DB logic here returning Domain Entity
123
+ return User(id=user_id, name="Alice")
124
+ ```
125
+
126
+ **3. Use Case (Application Layer)**
127
+ *File: `src/application/use_cases/get_user.py`*
128
+ ```python
129
+ from src.application.ports.user_repository import UserRepository
130
+ from src.domain.entities.user import User
131
+ from src.domain.exceptions import UserNotFoundError
132
+
133
+ class GetUserUseCase:
134
+ def __init__(self, user_repo: UserRepository):
135
+ self.user_repo = user_repo
136
+
137
+ def execute(self, user_id: str) -> User:
138
+ user = self.user_repo.get_by_id(user_id)
139
+ if not user:
140
+ raise UserNotFoundError(f"User {user_id} not found")
141
+ return user
142
+ ```
143
+
144
+ **4. Controller (Presentation Layer)**
145
+ *File: `src/presentation/controllers/user_controller.py`*
146
+ ```python
147
+ from fastapi import APIRouter, Depends, HTTPException
148
+ from src.application.use_cases.get_user import GetUserUseCase
149
+ from src.infrastructure.database.postgres_user_repository import PostgresUserRepository
150
+ from src.domain.exceptions import UserNotFoundError
151
+
152
+ router = APIRouter()
153
+
154
+ # Poor man's DI for FastAPI
155
+ def get_user_use_case() -> GetUserUseCase:
156
+ repo = PostgresUserRepository(db_session=None)
157
+ return GetUserUseCase(user_repo=repo)
158
+
159
+ @router.get("/users/{user_id}")
160
+ def get_user(user_id: str, use_case: GetUserUseCase = Depends(get_user_use_case)):
161
+ try:
162
+ return use_case.execute(user_id)
163
+ except UserNotFoundError as e:
164
+ raise HTTPException(status_code=404, detail=str(e))
165
+ ```
166
+ """
167
+ elif framework == 'django':
168
+ md += """### Example: Django + Hexagonal Architecture
169
+
170
+ **Note on Django**: Do NOT put business logic in Django Views or Models. Use Django ONLY as the `infrastructure/` and `presentation/` layers.
171
+
172
+ **1. Port (Application Layer)**
173
+ *File: `src/application/ports/user_repository.py`*
174
+ ```python
175
+ import abc
176
+ from src.domain.entities.user import User
177
+
178
+ class UserRepository(abc.ABC):
179
+ @abc.abstractmethod
180
+ def get_by_id(self, user_id: str) -> User | None:
181
+ pass
182
+ ```
183
+
184
+ **2. Adapter (Infrastructure Layer)**
185
+ *File: `src/infrastructure/database/django_user_repository.py`*
186
+ ```python
187
+ from src.application.ports.user_repository import UserRepository
188
+ from src.domain.entities.user import User
189
+ from myapp.models import DjangoUserModel # Django ORM Model
190
+
191
+ class DjangoUserRepository(UserRepository):
192
+ def get_by_id(self, user_id: str) -> User | None:
193
+ try:
194
+ orm_user = DjangoUserModel.objects.get(id=user_id)
195
+ return User(id=str(orm_user.id), name=orm_user.name) # Map ORM to Domain
196
+ except DjangoUserModel.DoesNotExist:
197
+ return None
198
+ ```
199
+
200
+ **3. Controller (Presentation Layer)**
201
+ *File: `src/presentation/views/user_views.py`*
202
+ ```python
203
+ from django.http import JsonResponse
204
+ from src.application.use_cases.get_user import GetUserUseCase
205
+ from src.infrastructure.database.django_user_repository import DjangoUserRepository
206
+ from src.domain.exceptions import UserNotFoundError
207
+
208
+ def get_user_view(request, user_id: str):
209
+ repo = DjangoUserRepository()
210
+ use_case = GetUserUseCase(user_repo=repo)
211
+
212
+ try:
213
+ user = use_case.execute(user_id)
214
+ return JsonResponse({"id": user.id, "name": user.name})
215
+ except UserNotFoundError as e:
216
+ return JsonResponse({"error": str(e)}, status=404)
217
+ ```
218
+ """
219
+ else:
220
+ md += """### Example: Pure Python + Hexagonal Architecture
221
+
222
+ **1. Port (Application Layer)**
223
+ *File: `src/application/ports/user_repository.py`*
224
+ ```python
225
+ from typing import Protocol
226
+ from src.domain.entities.user import User
227
+
228
+ class UserRepository(Protocol):
229
+ def get_by_id(self, user_id: str) -> User | None:
230
+ ...
231
+ ```
232
+
233
+ **2. Use Case (Application Layer)**
234
+ *File: `src/application/use_cases/get_user.py`*
235
+ ```python
236
+ from src.application.ports.user_repository import UserRepository
237
+ from src.domain.entities.user import User
238
+
239
+ class GetUserUseCase:
240
+ def __init__(self, user_repo: UserRepository):
241
+ self.user_repo = user_repo
242
+
243
+ def execute(self, user_id: str) -> User:
244
+ return self.user_repo.get_by_id(user_id)
245
+ ```
246
+
247
+ **3. Handler (Presentation Layer - Lambda)**
248
+ *File: `src/presentation/handlers/user_handler.py`*
249
+ ```python
250
+ from src.application.use_cases.get_user import GetUserUseCase
251
+ from src.infrastructure.database.dynamo_user_repository import DynamoUserRepository
252
+
253
+ # Initialize dependencies at the module level for Lambda cold starts
254
+ repo = DynamoUserRepository()
255
+ use_case = GetUserUseCase(user_repo=repo)
256
+
257
+ def lambda_handler(event, context):
258
+ user_id = event.get('pathParameters', {}).get('userId')
259
+ user = use_case.execute(user_id)
260
+ return {"statusCode": 200, "body": user.to_json()}
261
+ ```
262
+ """
263
+ else: # Node.js
264
+ if use_di:
265
+ md += """### Example: Node.js + TypeScript + InversifyJS
266
+
267
+ **1. Port (Application Layer)**
268
+ *File: `src/application/ports/IUserRepository.ts`*
269
+ ```typescript
270
+ import { User } from "../../domain/entities/User";
271
+
272
+ export const TYPES = {
273
+ IUserRepository: Symbol.for("IUserRepository"),
274
+ GetUserUseCase: Symbol.for("GetUserUseCase"),
275
+ };
276
+
277
+ export interface IUserRepository {
278
+ getById(userId: string): Promise<User | null>;
279
+ }
280
+ ```
281
+
282
+ **2. Adapter (Infrastructure Layer)**
283
+ *File: `src/infrastructure/database/PostgresUserRepository.ts`*
284
+ ```typescript
285
+ import { injectable } from "inversify";
286
+ import "reflect-metadata";
287
+ import { IUserRepository } from "../../application/ports/IUserRepository";
288
+ import { User } from "../../domain/entities/User";
289
+
290
+ @injectable()
291
+ export class PostgresUserRepository implements IUserRepository {
292
+ async getById(userId: string): Promise<User | null> {
293
+ // DB Logic returning Domain Entity
294
+ return new User(userId, "Alice");
295
+ }
296
+ }
297
+ ```
298
+
299
+ **3. Use Case (Application Layer)**
300
+ *File: `src/application/useCases/GetUserUseCase.ts`*
301
+ ```typescript
302
+ import { inject, injectable } from "inversify";
303
+ import "reflect-metadata";
304
+ import { IUserRepository, TYPES } from "../ports/IUserRepository";
305
+ import { User } from "../../domain/entities/User";
306
+
307
+ @injectable()
308
+ export class GetUserUseCase {
309
+ constructor(
310
+ @inject(TYPES.IUserRepository) private userRepository: IUserRepository
311
+ ) {}
312
+
313
+ async execute(userId: string): Promise<User> {
314
+ const user = await this.userRepository.getById(userId);
315
+ if (!user) throw new Error("User not found");
316
+ return user;
317
+ }
318
+ }
319
+ ```
320
+
321
+ **4. DI Container Setup (Infrastructure Layer)**
322
+ *File: `src/infrastructure/di/container.ts`*
323
+ ```typescript
324
+ import { Container } from "inversify";
325
+ import { TYPES, IUserRepository } from "../../application/ports/IUserRepository";
326
+ import { PostgresUserRepository } from "../database/PostgresUserRepository";
327
+ import { GetUserUseCase } from "../../application/useCases/GetUserUseCase";
328
+
329
+ const container = new Container();
330
+
331
+ container.bind<IUserRepository>(TYPES.IUserRepository).to(PostgresUserRepository);
332
+ container.bind<GetUserUseCase>(TYPES.GetUserUseCase).to(GetUserUseCase);
333
+
334
+ export { container };
335
+ ```
336
+
337
+ **5. Controller (Presentation Layer)**
338
+ *File: `src/presentation/controllers/UserController.ts`*
339
+ ```typescript
340
+ import { Request, Response } from "express";
341
+ import { container } from "../../infrastructure/di/container";
342
+ import { TYPES } from "../../application/ports/IUserRepository";
343
+ import { GetUserUseCase } from "../../application/useCases/GetUserUseCase";
344
+
345
+ export class UserController {
346
+ async getUser(req: Request, res: Response) {
347
+ const useCase = container.get<GetUserUseCase>(TYPES.GetUserUseCase);
348
+ try {
349
+ const user = await useCase.execute(req.params.id);
350
+ res.json(user);
351
+ } catch (error) {
352
+ res.status(404).json({ error: error.message });
353
+ }
354
+ }
355
+ }
356
+ ```
357
+ """
358
+ else:
359
+ md += """### Example: Node.js + TypeScript (Manual DI)
360
+
361
+ **1. Port (Application Layer)**
362
+ *File: `src/application/ports/IUserRepository.ts`*
363
+ ```typescript
364
+ import { User } from "../../domain/entities/User";
365
+
366
+ export interface IUserRepository {
367
+ getById(userId: string): Promise<User | null>;
368
+ }
369
+ ```
370
+
371
+ **2. Adapter (Infrastructure Layer)**
372
+ *File: `src/infrastructure/database/PostgresUserRepository.ts`*
373
+ ```typescript
374
+ import { IUserRepository } from "../../application/ports/IUserRepository";
375
+ import { User } from "../../domain/entities/User";
376
+
377
+ export class PostgresUserRepository implements IUserRepository {
378
+ async getById(userId: string): Promise<User | null> {
379
+ // DB Logic returning Domain Entity
380
+ return new User(userId, "Alice");
381
+ }
382
+ }
383
+ ```
384
+
385
+ **3. Use Case (Application Layer)**
386
+ *File: `src/application/useCases/GetUserUseCase.ts`*
387
+ ```typescript
388
+ import { IUserRepository } from "../ports/IUserRepository";
389
+ import { User } from "../../domain/entities/User";
390
+
391
+ export class GetUserUseCase {
392
+ constructor(private userRepository: IUserRepository) {}
393
+
394
+ async execute(userId: string): Promise<User> {
395
+ const user = await this.userRepository.getById(userId);
396
+ if (!user) throw new Error("User not found");
397
+ return user;
398
+ }
399
+ }
400
+ ```
401
+
402
+ **4. Controller (Presentation Layer)**
403
+ *File: `src/presentation/controllers/UserController.ts`*
404
+ ```typescript
405
+ import { Request, Response } from "express";
406
+ import { GetUserUseCase } from "../../application/useCases/GetUserUseCase";
407
+ import { PostgresUserRepository } from "../../infrastructure/database/PostgresUserRepository";
408
+
409
+ export class UserController {
410
+ async getUser(req: Request, res: Response) {
411
+ const repo = new PostgresUserRepository();
412
+ const useCase = new GetUserUseCase(repo);
413
+ try {
414
+ const user = await useCase.execute(req.params.id);
415
+ res.json(user);
416
+ } catch (error) {
417
+ res.status(404).json({ error: error.message });
418
+ }
419
+ }
420
+ }
421
+ ```
422
+ """
423
+
424
+ return md
@@ -8,7 +8,7 @@ with open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f:
8
8
 
9
9
  setup(
10
10
  name="devhive",
11
- version="0.1.23", # Bumping from the last deployed version 0.1.21
11
+ version="0.1.25",
12
12
  packages=find_packages(),
13
13
  include_package_data=True,
14
14
  install_requires=[
@@ -29,5 +29,5 @@ setup(
29
29
  "License :: OSI Approved :: MIT License",
30
30
  "Operating System :: OS Independent",
31
31
  ],
32
- python_requires='>=3.8',
32
+ python_requires='>=3.7',
33
33
  )
@@ -0,0 +1,160 @@
1
+ # Frontend Architecture & AI Agent Guidelines
2
+
3
+ This `AGENTS.md` (or `GUIDELINES.md`) file serves as the strict instruction manual for OpenCode and DevHive agents. It defines the technical stack, architectural patterns, and coding conventions for this frontend project.
4
+
5
+ ## 🛠️ 1. Tech Stack
6
+ - **Framework**: Next.js 15 (App Router)
7
+ - **Library**: React 19
8
+ - **Language**: TypeScript (Strict Mode)
9
+ - **Styling**: Tailwind CSS v3/v4 + `clsx` + `tailwind-merge`
10
+ - **Components**: shadcn/ui (Radix UI primitives)
11
+ - **Icons**: Lucide React
12
+ - **Data Fetching**: React Server Components (RSC) & Server Actions
13
+
14
+ ## 🧠 2. OpenCode Skills to Load
15
+ Agents **MUST** load the following specialized skills before executing tasks:
16
+ - `frontend-developer`: For modern React 19 / Next.js 15 patterns.
17
+ - `frontend-design`: For high-quality, non-generic UI aesthetics.
18
+ - `shadcn`: For proper installation and composition of shadcn/ui components.
19
+ - `theme-factory`: For applying cohesive color palettes and typography.
20
+ - `architecture-patterns`: For maintaining clean separation of concerns.
21
+
22
+ ## 📂 3. Project Structure (Feature-Based Architecture)
23
+ For maximum scalability and maintainability, the project follows a feature-based architecture within the `src/` directory.
24
+
25
+ ```text
26
+ src/
27
+ ├── app/ # Next.js App Router (Pages, Layouts, API Routes)
28
+ │ ├── (auth)/ # Route groups for logical separation
29
+ │ ├── dashboard/ # Dashboard routes
30
+ │ └── layout.tsx # Root layout (Providers, Fonts, Metadata)
31
+ ├── components/
32
+ │ ├── ui/ # Pure shadcn/ui components (DO NOT EDIT DIRECTLY unless styling)
33
+ │ └── shared/ # Reusable global components (Navbar, Footer, etc.)
34
+ ├── features/ # Feature-based modules (THE CORE OF THE APP)
35
+ │ ├── users/ # "Users" feature module
36
+ │ │ ├── actions.ts # Server Actions for this feature
37
+ │ │ ├── components/ # Feature-specific React components
38
+ │ │ └── types.ts # Feature-specific TypeScript interfaces
39
+ │ └── products/ # "Products" feature module
40
+ ├── lib/ # Utility functions (utils.ts, formatting, constants)
41
+ └── hooks/ # Global custom React hooks
42
+ ```
43
+
44
+ ## 📐 4. Architectural Rules & Best Practices
45
+
46
+ 1. **Default to Server Components (RSC)**:
47
+ - All components inside `app/` and `features/` MUST be Server Components by default to optimize bundle size and SEO.
48
+ - ONLY add the `"use client"` directive at the very top of a file if the component requires interactivity (`useState`, `useEffect`, `onClick`, browser APIs).
49
+ - Keep Client Components as low in the tree (leaf nodes) as possible.
50
+
51
+ 2. **Server Actions for Mutations**:
52
+ - Do NOT build traditional API routes (`route.ts`) for internal app data mutations.
53
+ - Use Next.js Server Actions (`"use server"`) placed in `src/features/[name]/actions.ts`.
54
+ - Always validate inputs inside Server Actions (using Zod or similar) before mutating data.
55
+
56
+ 3. **Shadcn/ui Usage**:
57
+ - Use the OpenCode CLI or `npx shadcn@latest add [component]` to install components.
58
+ - Combine UI components to build complex blocks (e.g., combining `Card`, `Button`, and `Input` to make a LoginForm).
59
+
60
+ 4. **Type Safety**:
61
+ - Avoid `any`. Define interfaces/types in `types.ts` files.
62
+ - Export types and reuse them across Server Actions and Client Components.
63
+
64
+ ## 💻 5. Code Examples
65
+
66
+ ### Example A: Data Fetching in a Server Component (RSC)
67
+ *File: `src/app/dashboard/page.tsx`*
68
+ ```tsx
69
+ import { Suspense } from "react";
70
+ import { getUserProfile } from "@/features/users/actions";
71
+ import { UserProfileCard } from "@/features/users/components/user-profile-card";
72
+ import { Skeleton } from "@/components/ui/skeleton";
73
+
74
+ // This is a Server Component (no "use client")
75
+ export default async function DashboardPage() {
76
+ // Fetch data directly on the server
77
+ const user = await getUserProfile();
78
+
79
+ return (
80
+ <main className="container mx-auto p-6">
81
+ <h1 className="text-3xl font-bold mb-6">Dashboard</h1>
82
+ <Suspense fallback={<Skeleton className="h-[200px] w-full rounded-xl" />}>
83
+ <UserProfileCard user={user} />
84
+ </Suspense>
85
+ </main>
86
+ );
87
+ }
88
+ ```
89
+
90
+ ### Example B: Server Action for Data Mutation
91
+ *File: `src/features/users/actions.ts`*
92
+ ```typescript
93
+ "use server";
94
+
95
+ import { revalidatePath } from "next/cache";
96
+
97
+ export type UpdateUserResponse = {
98
+ success: boolean;
99
+ message: string;
100
+ };
101
+
102
+ export async function updateUserName(formData: FormData): Promise<UpdateUserResponse> {
103
+ const newName = formData.get("name") as string;
104
+
105
+ if (!newName || newName.length < 3) {
106
+ return { success: false, message: "Name must be at least 3 characters." };
107
+ }
108
+
109
+ // Perform database mutation here...
110
+ // await db.user.update(...)
111
+
112
+ // Revalidate the cache so the UI updates instantly
113
+ revalidatePath("/dashboard");
114
+
115
+ return { success: true, message: "Profile updated successfully." };
116
+ }
117
+ ```
118
+
119
+ ### Example C: Client Component using Shadcn/ui & Server Actions
120
+ *File: `src/features/users/components/edit-name-form.tsx`*
121
+ ```tsx
122
+ "use client";
123
+
124
+ import { useState, useTransition } from "react";
125
+ import { updateUserName } from "@/features/users/actions";
126
+ import { Button } from "@/components/ui/button";
127
+ import { Input } from "@/components/ui/input";
128
+ import { toast } from "@/components/ui/use-toast"; // shadcn toast
129
+
130
+ export function EditNameForm() {
131
+ const [isPending, startTransition] = useTransition();
132
+
133
+ const handleSubmit = (formData: FormData) => {
134
+ startTransition(async () => {
135
+ const result = await updateUserName(formData);
136
+
137
+ if (result.success) {
138
+ toast({ title: "Success", description: result.message });
139
+ } else {
140
+ toast({ title: "Error", description: result.message, variant: "destructive" });
141
+ }
142
+ });
143
+ };
144
+
145
+ return (
146
+ <form action={handleSubmit} className="flex gap-4 items-center">
147
+ <Input
148
+ name="name"
149
+ placeholder="Enter new name"
150
+ required
151
+ disabled={isPending}
152
+ className="max-w-sm"
153
+ />
154
+ <Button type="submit" disabled={isPending}>
155
+ {isPending ? "Saving..." : "Save Name"}
156
+ </Button>
157
+ </form>
158
+ );
159
+ }
160
+ ```
File without changes
File without changes