forked from mengyxu/noob-components
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
298 lines
9.1 KiB
298 lines
9.1 KiB
#!/usr/bin/env python3 |
|
""" |
|
Create Bootstrap Task for First-Time Setup. |
|
|
|
Creates a guided task to help users fill in project guidelines |
|
after initializing Trellis for the first time. |
|
|
|
Usage: |
|
python3 create_bootstrap.py [project-type] |
|
|
|
Arguments: |
|
project-type: frontend | backend | fullstack (default: fullstack) |
|
|
|
Prerequisites: |
|
- .trellis/.developer must exist (run init_developer.py first) |
|
|
|
Creates: |
|
.trellis/tasks/00-bootstrap-guidelines/ |
|
- task.json # Task metadata |
|
- prd.md # Task description and guidance |
|
""" |
|
|
|
from __future__ import annotations |
|
|
|
import json |
|
import sys |
|
from datetime import datetime |
|
from pathlib import Path |
|
|
|
from common.paths import ( |
|
DIR_WORKFLOW, |
|
DIR_SCRIPTS, |
|
DIR_TASKS, |
|
get_repo_root, |
|
get_developer, |
|
get_tasks_dir, |
|
set_current_task, |
|
) |
|
from common.config import get_spec_base, resolve_package |
|
|
|
|
|
# ============================================================================= |
|
# Constants |
|
# ============================================================================= |
|
|
|
TASK_NAME = "00-bootstrap-guidelines" |
|
|
|
|
|
# ============================================================================= |
|
# PRD Content |
|
# ============================================================================= |
|
|
|
def write_prd_header() -> str: |
|
"""Write PRD header section.""" |
|
return """# Bootstrap: Fill Project Development Guidelines |
|
|
|
## Purpose |
|
|
|
Welcome to Trellis! This is your first task. |
|
|
|
AI agents use `.trellis/spec/` to understand YOUR project's coding conventions. |
|
**Starting from scratch = AI writes generic code that doesn't match your project style.** |
|
|
|
Filling these guidelines is a one-time setup that pays off for every future AI session. |
|
|
|
--- |
|
|
|
## Your Task |
|
|
|
Fill in the guideline files based on your **existing codebase**. |
|
""" |
|
|
|
|
|
def write_prd_backend_section(spec_base: str) -> str: |
|
"""Write PRD backend section.""" |
|
return f""" |
|
|
|
### Backend Guidelines |
|
|
|
| File | What to Document | |
|
|------|------------------| |
|
| `.trellis/{spec_base}/backend/directory-structure.md` | Where different file types go (routes, services, utils) | |
|
| `.trellis/{spec_base}/backend/database-guidelines.md` | ORM, migrations, query patterns, naming conventions | |
|
| `.trellis/{spec_base}/backend/error-handling.md` | How errors are caught, logged, and returned | |
|
| `.trellis/{spec_base}/backend/logging-guidelines.md` | Log levels, format, what to log | |
|
| `.trellis/{spec_base}/backend/quality-guidelines.md` | Code review standards, testing requirements | |
|
""" |
|
|
|
|
|
def write_prd_frontend_section(spec_base: str) -> str: |
|
"""Write PRD frontend section.""" |
|
return f""" |
|
|
|
### Frontend Guidelines |
|
|
|
| File | What to Document | |
|
|------|------------------| |
|
| `.trellis/{spec_base}/frontend/directory-structure.md` | Component/page/hook organization | |
|
| `.trellis/{spec_base}/frontend/component-guidelines.md` | Component patterns, props conventions | |
|
| `.trellis/{spec_base}/frontend/hook-guidelines.md` | Custom hook naming, patterns | |
|
| `.trellis/{spec_base}/frontend/state-management.md` | State library, patterns, what goes where | |
|
| `.trellis/{spec_base}/frontend/type-safety.md` | TypeScript conventions, type organization | |
|
| `.trellis/{spec_base}/frontend/quality-guidelines.md` | Linting, testing, accessibility | |
|
""" |
|
|
|
|
|
def write_prd_footer() -> str: |
|
"""Write PRD footer section.""" |
|
return """ |
|
|
|
### Thinking Guides (Optional) |
|
|
|
The `.trellis/spec/guides/` directory contains thinking guides that are already |
|
filled with general best practices. You can customize them for your project if needed. |
|
|
|
--- |
|
|
|
## How to Fill Guidelines |
|
|
|
### Principle: Document Reality, Not Ideals |
|
|
|
Write what your codebase **actually does**, not what you wish it did. |
|
AI needs to match existing patterns, not introduce new ones. |
|
|
|
### Steps |
|
|
|
1. **Look at existing code** - Find 2-3 examples of each pattern |
|
2. **Document the pattern** - Describe what you see |
|
3. **Include file paths** - Reference real files as examples |
|
4. **List anti-patterns** - What does your team avoid? |
|
|
|
--- |
|
|
|
## Tips for Using AI |
|
|
|
Ask AI to help analyze your codebase: |
|
|
|
- "Look at my codebase and document the patterns you see" |
|
- "Analyze my code structure and summarize the conventions" |
|
- "Find error handling patterns and document them" |
|
|
|
The AI will read your code and help you document it. |
|
|
|
--- |
|
|
|
## Completion Checklist |
|
|
|
- [ ] Guidelines filled for your project type |
|
- [ ] At least 2-3 real code examples in each guideline |
|
- [ ] Anti-patterns documented |
|
|
|
When done: |
|
|
|
```bash |
|
python3 ./.trellis/scripts/task.py finish |
|
python3 ./.trellis/scripts/task.py archive 00-bootstrap-guidelines |
|
``` |
|
|
|
--- |
|
|
|
## Why This Matters |
|
|
|
After completing this task: |
|
|
|
1. AI will write code that matches your project style |
|
2. Relevant `/trellis:before-*-dev` commands will inject real context |
|
3. `/trellis:check-*` commands will validate against your actual standards |
|
4. Future developers (human or AI) will onboard faster |
|
""" |
|
|
|
|
|
def write_prd(task_dir: Path, project_type: str, spec_base: str) -> None: |
|
"""Write prd.md file.""" |
|
content = write_prd_header() |
|
|
|
if project_type == "frontend": |
|
content += write_prd_frontend_section(spec_base) |
|
elif project_type == "backend": |
|
content += write_prd_backend_section(spec_base) |
|
else: # fullstack |
|
content += write_prd_backend_section(spec_base) |
|
content += write_prd_frontend_section(spec_base) |
|
|
|
content += write_prd_footer() |
|
|
|
prd_file = task_dir / "prd.md" |
|
prd_file.write_text(content, encoding="utf-8") |
|
|
|
|
|
# ============================================================================= |
|
# Task JSON |
|
# ============================================================================= |
|
|
|
def write_task_json(task_dir: Path, developer: str, project_type: str, spec_base: str) -> None: |
|
"""Write task.json file.""" |
|
today = datetime.now().strftime("%Y-%m-%d") |
|
|
|
# Generate subtasks and related files based on project type |
|
if project_type == "frontend": |
|
subtasks = [ |
|
{"name": "Fill frontend guidelines", "status": "pending"}, |
|
{"name": "Add code examples", "status": "pending"}, |
|
] |
|
related_files = [f".trellis/{spec_base}/frontend/"] |
|
elif project_type == "backend": |
|
subtasks = [ |
|
{"name": "Fill backend guidelines", "status": "pending"}, |
|
{"name": "Add code examples", "status": "pending"}, |
|
] |
|
related_files = [f".trellis/{spec_base}/backend/"] |
|
else: # fullstack |
|
subtasks = [ |
|
{"name": "Fill backend guidelines", "status": "pending"}, |
|
{"name": "Fill frontend guidelines", "status": "pending"}, |
|
{"name": "Add code examples", "status": "pending"}, |
|
] |
|
related_files = [f".trellis/{spec_base}/backend/", f".trellis/{spec_base}/frontend/"] |
|
|
|
task_data = { |
|
"id": TASK_NAME, |
|
"name": "Bootstrap Guidelines", |
|
"description": "Fill in project development guidelines for AI agents", |
|
"status": "in_progress", |
|
"dev_type": "docs", |
|
"priority": "P1", |
|
"creator": developer, |
|
"assignee": developer, |
|
"createdAt": today, |
|
"completedAt": None, |
|
"commit": None, |
|
"subtasks": subtasks, |
|
"children": [], |
|
"parent": None, |
|
"relatedFiles": related_files, |
|
"notes": f"First-time setup task created by trellis init ({project_type} project)", |
|
"meta": {}, |
|
} |
|
|
|
task_json = task_dir / "task.json" |
|
task_json.write_text(json.dumps(task_data, indent=2, ensure_ascii=False), encoding="utf-8") |
|
|
|
|
|
# ============================================================================= |
|
# Main |
|
# ============================================================================= |
|
|
|
def main() -> int: |
|
"""Main entry point.""" |
|
# Parse project type argument |
|
project_type = "fullstack" |
|
if len(sys.argv) > 1: |
|
project_type = sys.argv[1] |
|
|
|
# Validate project type |
|
if project_type not in ("frontend", "backend", "fullstack"): |
|
print(f"Unknown project type: {project_type}, defaulting to fullstack") |
|
project_type = "fullstack" |
|
|
|
repo_root = get_repo_root() |
|
developer = get_developer(repo_root) |
|
|
|
# Check developer initialized |
|
if not developer: |
|
print("Error: Developer not initialized") |
|
print(f"Run: python3 ./{DIR_WORKFLOW}/{DIR_SCRIPTS}/init_developer.py <your-name>") |
|
return 1 |
|
|
|
# Resolve spec base path (monorepo: spec/<package>, single-repo: spec) |
|
package = resolve_package(repo_root=repo_root) |
|
spec_base = get_spec_base(package, repo_root) |
|
|
|
tasks_dir = get_tasks_dir(repo_root) |
|
task_dir = tasks_dir / TASK_NAME |
|
relative_path = f"{DIR_WORKFLOW}/{DIR_TASKS}/{TASK_NAME}" |
|
|
|
# Check if already exists |
|
if task_dir.exists(): |
|
print(f"Bootstrap task already exists: {relative_path}") |
|
return 0 |
|
|
|
# Create task directory |
|
task_dir.mkdir(parents=True, exist_ok=True) |
|
|
|
# Write files |
|
write_task_json(task_dir, developer, project_type, spec_base) |
|
write_prd(task_dir, project_type, spec_base) |
|
|
|
# Set as current task |
|
set_current_task(relative_path, repo_root) |
|
|
|
# Silent output - init command handles user-facing messages |
|
# Only output the task path for programmatic use |
|
print(relative_path) |
|
return 0 |
|
|
|
|
|
if __name__ == "__main__": |
|
sys.exit(main())
|
|
|