-
Notifications
You must be signed in to change notification settings - Fork 5
feat(config): unified CODEFRAME.md workflow config (#398) #445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -82,6 +82,11 @@ def init( | |||||||||||||||||||||||||||||||||||||||||||||||||||
| "--tech-stack-interactive", "-i", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| help="Interactively configure tech stack", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| generate_config: bool = typer.Option( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--generate-config", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| help="Generate starter CODEFRAME.md with project configuration", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Initialize a CodeFRAME workspace for a repository. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -99,6 +104,8 @@ def init( | |||||||||||||||||||||||||||||||||||||||||||||||||||
| codeframe init . --tech-stack "Rust project using cargo" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| codeframe init . --tech-stack "TypeScript monorepo with pnpm, Next.js frontend, FastAPI backend" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| codeframe init . --tech-stack-interactive | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| codeframe init . --generate-config | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| codeframe init . --detect --generate-config | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| from codeframe.core.workspace import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| create_or_load_workspace, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -170,6 +177,15 @@ def init( | |||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.print(f" Hook after_init: [yellow]failed[/yellow] ({hook_result.stderr[:100]})") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Generate CODEFRAME.md if requested | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if generate_config: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| config_content = _generate_codeframe_md( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| tech_stack=final_tech_stack or "", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| config_path = repo_path / "CODEFRAME.md" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| config_path.write_text(config_content) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.print(" Generated: CODEFRAME.md") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.print() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.print("Next steps:") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.print(" codeframe prd add <file.md> Add a PRD") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -317,6 +333,58 @@ def _interactive_tech_stack() -> str: | |||||||||||||||||||||||||||||||||||||||||||||||||||
| return tech_stack | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _generate_codeframe_md(tech_stack: str = "") -> str: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Generate a starter CODEFRAME.md file with YAML front matter and body. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| tech_stack: Natural language tech stack description. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| Returns: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Complete CODEFRAME.md content string. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import yaml as _yaml | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml_section: dict = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| "engine": "react", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if tech_stack: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml_section["tech_stack"] = tech_stack | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Detect gates from tech stack | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| gates: list[str] = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if tech_stack: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ts_lower = tech_stack.lower() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if "python" in ts_lower or "pytest" in ts_lower: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| gates.extend(["ruff", "pytest"]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif "typescript" in ts_lower or "jest" in ts_lower: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| gates.extend(["eslint", "jest"]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if gates: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml_section["gates"] = gates | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+353
to
+362
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Infer gates for every detected stack, not just the first one.
🛠️ Suggested fix # Detect gates from tech stack
gates: list[str] = []
if tech_stack:
ts_lower = tech_stack.lower()
if "python" in ts_lower or "pytest" in ts_lower:
gates.extend(["ruff", "pytest"])
- elif "typescript" in ts_lower or "jest" in ts_lower:
- gates.extend(["eslint", "jest"])
+ if any(token in ts_lower for token in ("typescript", "javascript", "jest", "vitest", "eslint")):
+ gates.append("eslint")
+ if "jest" in ts_lower:
+ gates.append("jest")
+ elif "vitest" in ts_lower:
+ gates.append("vitest")
+ gates = list(dict.fromkeys(gates))
if gates:
yaml_section["gates"] = gates📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml_section["batch"] = {"max_parallel": 2, "default_strategy": "auto"} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| yaml_section["agent"] = {"max_iterations": 30, "verbose": False} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| front_matter = _yaml.dump(yaml_section, default_flow_style=False, sort_keys=False) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| body = """# Project Agent Instructions | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Coding Standards | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Follow existing code patterns and conventions | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Write clear, self-documenting code | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Include appropriate error handling | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Always Do | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Run tests before considering a task complete | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Follow the project's existing file structure | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Never Do | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Delete or overwrite files without understanding their purpose | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Introduce new dependencies without justification | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| return f"---\n{front_matter}---\n\n{body}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| @app.command() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| def status( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| repo_path: Optional[Path] = typer.Argument( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid clobbering an existing
CODEFRAME.md.Re-running
cf init --generate-configcurrently truncates any checked-inCODEFRAME.mdwithout confirmation. Since that file now carries both runtime settings and agent instructions, this should fail fast or require an explicit force flag.🛠️ Suggested guard
# Generate CODEFRAME.md if requested if generate_config: - config_content = _generate_codeframe_md( - tech_stack=final_tech_stack or "", - ) config_path = repo_path / "CODEFRAME.md" - config_path.write_text(config_content) + if config_path.exists(): + console.print("[red]Error:[/red] CODEFRAME.md already exists. Use --force to overwrite it.") + raise typer.Exit(1) + config_content = _generate_codeframe_md(tech_stack=final_tech_stack or "") + config_path.write_text(config_content, encoding="utf-8") console.print(" Generated: CODEFRAME.md")🤖 Prompt for AI Agents