From 348ce5d49d6308461da7d6e7c8189ae63ba9a764 Mon Sep 17 00:00:00 2001 From: Eric Nolte Date: Fri, 5 Sep 2025 12:30:26 -0400 Subject: [PATCH] feat: add cursor support --- .github/workflows/manual-release.yml | 35 +++++++++++++++++++++------- .github/workflows/release.yml | 30 ++++++++++++++++++++---- README.md | 4 +++- scripts/update-agent-context.sh | 17 ++++++++++---- src/specify_cli/__init__.py | 35 +++++++++++++++++++++------- templates/plan-template.md | 6 ++--- 6 files changed, 98 insertions(+), 29 deletions(-) mode change 100755 => 100644 scripts/update-agent-context.sh diff --git a/.github/workflows/manual-release.yml b/.github/workflows/manual-release.yml index 02515174ac..d6a2df7f80 100644 --- a/.github/workflows/manual-release.yml +++ b/.github/workflows/manual-release.yml @@ -126,20 +126,38 @@ jobs: echo "⚠️ agent_templates/copilot folder not found" fi + # Create Cursor CLI package + echo "Creating Cursor CLI package..." + mkdir -p sdd-cursor-package + cp -r sdd-package-base/* sdd-cursor-package/ + # Add any agent_templates/cursor files if you have them (optional) + # mkdir -p sdd-cursor-package/.cursor + # cp -r agent_templates/cursor sdd-cursor-package/.cursor + echo "✓ Created Cursor CLI package" + + # Create Cursor IDE package + echo "Creating Cursor IDE package..." + mkdir -p sdd-cursor-ide-package + cp -r sdd-package-base/* sdd-cursor-ide-package/ + mkdir -p sdd-cursor-ide-package/.cursor/commands + generate_commands "cursor-ide" "md" "$ARGUMENTS" "sdd-cursor-ide-package/.cursor/commands" + echo "✓ Created Cursor IDE package" + # Create archive files for each package echo "Creating archive files..." cd sdd-claude-package && zip -r ../spec-kit-template-claude-${{ steps.version.outputs.new_version }}.zip . && cd .. - cd sdd-gemini-package && zip -r ../spec-kit-template-gemini-${{ steps.version.outputs.new_version }}.zip . && cd .. - cd sdd-copilot-package && zip -r ../spec-kit-template-copilot-${{ steps.version.outputs.new_version }}.zip . && cd .. - + cd sdd-cursor-package && zip -r ../spec-kit-template-cursor-${{ steps.version.outputs.new_version }}.zip . && cd .. + cd sdd-cursor-ide-package && zip -r ../spec-kit-template-cursor-ide-${{ steps.version.outputs.new_version }}.zip . && cd .. + echo "" echo "📦 Packages created:" echo "Claude: $(ls -lh spec-kit-template-claude-*.zip | awk '{print $5}')" echo "Gemini: $(ls -lh spec-kit-template-gemini-*.zip | awk '{print $5}')" echo "Copilot: $(ls -lh spec-kit-template-copilot-*.zip | awk '{print $5}')" - echo "Copilot: $(ls -lh sdd-template-copilot-*.zip | awk '{print $5}')" + echo "Cursor: $(ls -lh spec-kit-template-cursor-*.zip | awk '{print $5}')" + echo "Cursor IDE: $(ls -lh spec-kit-template-cursor-ide-*.zip | awk '{print $5}')" - name: Generate detailed release notes run: | @@ -164,15 +182,14 @@ jobs: cat > release_notes.md << EOF Template release ${{ steps.version.outputs.new_version }} - Updated specification-driven development templates for GitHub Copilot, Claude Code, and Gemini CLI. + Updated specification-driven development templates for GitHub Copilot, Claude Code, Gemini CLI, Cursor CLI, and Cursor IDE. Download the template for your preferred AI assistant: - spec-kit-template-copilot-${{ steps.version.outputs.new_version }}.zip - spec-kit-template-claude-${{ steps.version.outputs.new_version }}.zip - spec-kit-template-gemini-${{ steps.version.outputs.new_version }}.zip - - Changes since $LAST_TAG: - $COMMITS + - spec-kit-template-cursor-${{ steps.version.outputs.new_version }}.zip + - spec-kit-template-cursor-ide-${{ steps.version.outputs.new_version }}.zip EOF - name: Create GitHub Release @@ -185,6 +202,8 @@ jobs: spec-kit-template-copilot-${{ steps.version.outputs.new_version }}.zip \ spec-kit-template-claude-${{ steps.version.outputs.new_version }}.zip \ spec-kit-template-gemini-${{ steps.version.outputs.new_version }}.zip \ + spec-kit-template-cursor-${{ steps.version.outputs.new_version }}.zip \ + spec-kit-template-cursor-ide-${{ steps.version.outputs.new_version }}.zip \ --title "Spec Kit Templates - $VERSION_NO_V" \ --notes-file release_notes.md env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a4a282a2c7..fea1974fd4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -141,13 +141,27 @@ jobs: generate_commands "copilot" "prompt.md" "\$ARGUMENTS" "sdd-copilot-package/.github/prompts" echo "Created GitHub Copilot package" + # Create Cursor CLI package + mkdir -p sdd-cursor-package + cp -r sdd-package-base/* sdd-cursor-package/ + mkdir -p sdd-cursor-package/.cursor/commands + generate_commands "cursor" "md" "$ARGUMENTS" "sdd-cursor-package/.cursor/commands" + echo "Created Cursor CLI package" + + # Create Cursor IDE package + mkdir -p sdd-cursor-ide-package + cp -r sdd-package-base/* sdd-cursor-ide-package/ + mkdir -p sdd-cursor-ide-package/.cursor/commands + generate_commands "cursor-ide" "md" "$ARGUMENTS" "sdd-cursor-ide-package/.cursor/commands" + echo "Created Cursor IDE package" + # Create archive files for each package cd sdd-claude-package && zip -r ../spec-kit-template-claude-${{ steps.get_tag.outputs.new_version }}.zip . && cd .. - cd sdd-gemini-package && zip -r ../spec-kit-template-gemini-${{ steps.get_tag.outputs.new_version }}.zip . && cd .. - cd sdd-copilot-package && zip -r ../spec-kit-template-copilot-${{ steps.get_tag.outputs.new_version }}.zip . && cd .. - + cd sdd-cursor-package && zip -r ../spec-kit-template-cursor-${{ steps.get_tag.outputs.new_version }}.zip . && cd .. + cd sdd-cursor-ide-package && zip -r ../spec-kit-template-cursor-ide-${{ steps.get_tag.outputs.new_version }}.zip . && cd .. + # List contents for verification echo "Claude package contents:" unzip -l spec-kit-template-claude-${{ steps.get_tag.outputs.new_version }}.zip | head -10 @@ -155,6 +169,10 @@ jobs: unzip -l spec-kit-template-gemini-${{ steps.get_tag.outputs.new_version }}.zip | head -10 echo "Copilot package contents:" unzip -l spec-kit-template-copilot-${{ steps.get_tag.outputs.new_version }}.zip | head -10 + echo "Cursor CLI package contents:" + unzip -l spec-kit-template-cursor-${{ steps.get_tag.outputs.new_version }}.zip | head -10 + echo "Cursor IDE package contents:" + unzip -l spec-kit-template-cursor-ide-${{ steps.get_tag.outputs.new_version }}.zip | head -10 - name: Generate release notes if: steps.check_release.outputs.exists == 'false' @@ -178,12 +196,14 @@ jobs: cat > release_notes.md << EOF Template release ${{ steps.get_tag.outputs.new_version }} - Updated specification-driven development templates for GitHub Copilot, Claude Code, and Gemini CLI. + Updated specification-driven development templates for GitHub Copilot, Claude Code, Gemini CLI, Cursor CLI, and Cursor IDE. Download the template for your preferred AI assistant: - spec-kit-template-copilot-${{ steps.get_tag.outputs.new_version }}.zip - spec-kit-template-claude-${{ steps.get_tag.outputs.new_version }}.zip - spec-kit-template-gemini-${{ steps.get_tag.outputs.new_version }}.zip + - spec-kit-template-cursor-${{ steps.get_tag.outputs.new_version }}.zip + - spec-kit-template-cursor-ide-${{ steps.get_tag.outputs.new_version }}.zip EOF echo "Generated release notes:" @@ -200,6 +220,8 @@ jobs: spec-kit-template-copilot-${{ steps.get_tag.outputs.new_version }}.zip \ spec-kit-template-claude-${{ steps.get_tag.outputs.new_version }}.zip \ spec-kit-template-gemini-${{ steps.get_tag.outputs.new_version }}.zip \ + spec-kit-template-cursor-${{ steps.get_tag.outputs.new_version }}.zip \ + spec-kit-template-cursor-ide-${{ steps.get_tag.outputs.new_version }}.zip \ --title "Spec Kit Templates - $VERSION_NO_V" \ --notes-file release_notes.md env: diff --git a/README.md b/README.md index 4f7a7a26e9..577ff3c378 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ Our research and experimentation focus on: ## 🔧 Prerequisites - **Linux/macOS** (or WSL2 on Windows) -- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), or [Gemini CLI](https://github.com/google-gemini/gemini-cli) +- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Cursor IDE](https://docs.cursor.com/), or [Cursor CLI](https://github.com/getcursor/cursor) (**experimental**) - [uv](https://docs.astral.sh/uv/) for package management - [Python 3.11+](https://www.python.org/downloads/) - [Git](https://git-scm.com/downloads) @@ -143,6 +143,8 @@ You will be prompted to select the AI agent you are using. You can also proactiv specify init --ai claude specify init --ai gemini specify init --ai copilot +specify init --ai cursor-ide # Cursor IDE +specify init --ai cursor # Cursor CLI (experimental) # Or in current directory: specify init --here --ai claude ``` diff --git a/scripts/update-agent-context.sh b/scripts/update-agent-context.sh old mode 100755 new mode 100644 index 51fa640b62..91a3168438 --- a/scripts/update-agent-context.sh +++ b/scripts/update-agent-context.sh @@ -14,6 +14,8 @@ NEW_PLAN="$FEATURE_DIR/plan.md" CLAUDE_FILE="$REPO_ROOT/CLAUDE.md" GEMINI_FILE="$REPO_ROOT/GEMINI.md" COPILOT_FILE="$REPO_ROOT/.github/copilot-instructions.md" +CURSOR_FILE="$REPO_ROOT/CURSOR.md" +CURSOR_IDE_FILE="$REPO_ROOT/.github/cursor-instructions.md" # Allow override via argument AGENT_TYPE="$1" @@ -197,20 +199,27 @@ case "$AGENT_TYPE" in "copilot") update_agent_file "$COPILOT_FILE" "GitHub Copilot" ;; + "cursor") + update_agent_file "$CURSOR_FILE" "Cursor CLI" + ;; + "cursor-ide") + update_agent_file "$CURSOR_IDE_FILE" "Cursor IDE" + ;; "") # Update all existing files [ -f "$CLAUDE_FILE" ] && update_agent_file "$CLAUDE_FILE" "Claude Code" [ -f "$GEMINI_FILE" ] && update_agent_file "$GEMINI_FILE" "Gemini CLI" [ -f "$COPILOT_FILE" ] && update_agent_file "$COPILOT_FILE" "GitHub Copilot" - + [ -f "$CURSOR_FILE" ] && update_agent_file "$CURSOR_FILE" "Cursor CLI" + [ -f "$CURSOR_IDE_FILE" ] && update_agent_file "$CURSOR_IDE_FILE" "Cursor IDE" # If no files exist, create based on current directory or ask user - if [ ! -f "$CLAUDE_FILE" ] && [ ! -f "$GEMINI_FILE" ] && [ ! -f "$COPILOT_FILE" ]; then + if [ ! -f "$CLAUDE_FILE" ] && [ ! -f "$GEMINI_FILE" ] && [ ! -f "$COPILOT_FILE" ] && [ ! -f "$CURSOR_FILE" ] && [ ! -f "$CURSOR_IDE_FILE" ]; then echo "No agent context files found. Creating Claude Code context file by default." update_agent_file "$CLAUDE_FILE" "Claude Code" fi ;; *) - echo "ERROR: Unknown agent type '$AGENT_TYPE'. Use: claude, gemini, copilot, or leave empty for all." + echo "ERROR: Unknown agent type '$AGENT_TYPE'. Use: claude, gemini, copilot, cursor, cursor-ide, or leave empty for all." exit 1 ;; esac @@ -231,4 +240,4 @@ echo "Usage: $0 [claude|gemini|copilot]" echo " - No argument: Update all existing agent context files" echo " - claude: Update only CLAUDE.md" echo " - gemini: Update only GEMINI.md" -echo " - copilot: Update only .github/copilot-instructions.md" \ No newline at end of file +echo " - copilot: Update only .github/copilot-instructions.md" diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index aa3cf3c839..354acbaa7f 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -51,7 +51,9 @@ AI_CHOICES = { "copilot": "GitHub Copilot", "claude": "Claude Code", - "gemini": "Gemini CLI" + "gemini": "Gemini CLI", + "cursor": "Cursor CLI", + "cursor-ide": "Cursor IDE" } # ASCII Art Banner @@ -385,11 +387,10 @@ def init_git_repo(project_path: Path, quiet: bool = False) -> bool: os.chdir(original_cwd) -def download_template_from_github(ai_assistant: str, download_dir: Path, *, verbose: bool = True, show_progress: bool = True): +def download_template_from_github(ai_assistant: str, download_dir: Path, *, verbose: bool = True, show_progress: bool = True, repo_owner: str = "github"): """Download the latest template release from GitHub using HTTP requests. Returns (zip_path, metadata_dict) """ - repo_owner = "github" repo_name = "spec-kit" if verbose: @@ -483,7 +484,7 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, verb return zip_path, metadata -def download_and_extract_template(project_path: Path, ai_assistant: str, is_current_dir: bool = False, *, verbose: bool = True, tracker: StepTracker | None = None) -> Path: +def download_and_extract_template(project_path: Path, ai_assistant: str, is_current_dir: bool = False, *, verbose: bool = True, tracker: StepTracker | None = None, repo_owner: str = "github") -> Path: """Download the latest release and extract it to create a new project. Returns project_path. Uses tracker if provided (with keys: fetch, download, extract, cleanup) """ @@ -497,7 +498,8 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, is_curr ai_assistant, current_dir, verbose=verbose and tracker is None, - show_progress=(tracker is None) + show_progress=(tracker is None), + repo_owner=repo_owner ) if tracker: tracker.complete("fetch", f"release {meta['release']} ({meta['size']:,} bytes)") @@ -638,10 +640,11 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, is_curr @app.command() def init( project_name: str = typer.Argument(None, help="Name for your new project directory (optional if using --here)"), - ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, or copilot"), + ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor, or cursor-ide"), ignore_agent_tools: bool = typer.Option(False, "--ignore-agent-tools", help="Skip checks for AI agent tools like Claude Code"), no_git: bool = typer.Option(False, "--no-git", help="Skip git repository initialization"), here: bool = typer.Option(False, "--here", help="Initialize project in the current directory instead of creating a new one"), + repo_owner: str = typer.Option("github", "--repo-owner", help="GitHub repo owner for template download (default: github)") ): """ Initialize a new Specify project from the latest template. @@ -737,8 +740,14 @@ def init( if not check_tool("gemini", "Install from: https://github.com/google-gemini/gemini-cli"): console.print("[red]Error:[/red] Gemini CLI is required for Gemini projects") agent_tool_missing = True + elif selected_ai == "cursor": + if not check_tool("cursor", "Install from: https://github.com/cursor/cursor-cli"): + console.print("[red]Error:[/red] Cursor CLI is required for Cursor CLI projects") + agent_tool_missing = True + elif selected_ai == "cursor-ide": + # Cursor IDE is an application, not a CLI tool, so skip tool check + pass # GitHub Copilot check is not needed as it's typically available in supported IDEs - if agent_tool_missing: console.print("\n[red]Required AI tool is missing![/red]") console.print("[yellow]Tip:[/yellow] Use --ignore-agent-tools to skip this check") @@ -770,7 +779,7 @@ def init( with Live(tracker.render(), console=console, refresh_per_second=8, transient=True) as live: tracker.attach_refresh(lambda: live.update(tracker.render())) try: - download_and_extract_template(project_path, selected_ai, here, verbose=False, tracker=tracker) + download_and_extract_template(project_path, selected_ai, here, verbose=False, tracker=tracker, repo_owner=repo_owner) # Git step if not no_git: @@ -823,6 +832,13 @@ def init( steps_lines.append(" - See GEMINI.md for all available commands") elif selected_ai == "copilot": steps_lines.append(f"{step_num}. Open in Visual Studio Code and use [bold cyan]/specify[/], [bold cyan]/plan[/], [bold cyan]/tasks[/] commands with GitHub Copilot") + elif selected_ai == "cursor": + steps_lines.append(f"{step_num}. Use / commands with Cursor CLI") + steps_lines.append(" - Run cursor /specify to create specifications") + steps_lines.append(" - Run cursor /plan to create implementation plans") + steps_lines.append(" - See CURSOR.md for all available commands") + elif selected_ai == "cursor-ide": + steps_lines.append(f"{step_num}. Open in Cursor IDE and use [bold cyan]/specify[/], [bold cyan]/plan[/], [bold cyan]/tasks[/] commands with Cursor IDE") step_num += 1 steps_lines.append(f"{step_num}. Update [bold magenta]CONSTITUTION.md[/bold magenta] with your project's non-negotiable principles") @@ -855,11 +871,12 @@ def check(): console.print("\n[cyan]Optional AI tools:[/cyan]") claude_ok = check_tool("claude", "Install from: https://docs.anthropic.com/en/docs/claude-code/setup") gemini_ok = check_tool("gemini", "Install from: https://github.com/google-gemini/gemini-cli") + cursor_ok = check_tool("cursor", "Install from: https://github.com/cursor/cursor-cli") console.print("\n[green]✓ Specify CLI is ready to use![/green]") if not git_ok: console.print("[yellow]Consider installing git for repository management[/yellow]") - if not (claude_ok or gemini_ok): + if not (claude_ok or gemini_ok or cursor_ok): console.print("[yellow]Consider installing an AI assistant for the best experience[/yellow]") diff --git a/templates/plan-template.md b/templates/plan-template.md index f28a655d47..7d7dabdf00 100644 --- a/templates/plan-template.md +++ b/templates/plan-template.md @@ -16,7 +16,7 @@ → Update Progress Tracking: Initial Constitution Check 4. Execute Phase 0 → research.md → If NEEDS CLARIFICATION remain: ERROR "Resolve unknowns" -5. Execute Phase 1 → contracts, data-model.md, quickstart.md, agent-specific template file (e.g., `CLAUDE.md` for Claude Code, `.github/copilot-instructions.md` for GitHub Copilot, or `GEMINI.md` for Gemini CLI). +5. Execute Phase 1 → contracts, data-model.md, quickstart.md, agent-specific template file (e.g., `CLAUDE.md` for Claude Code, `.github/copilot-instructions.md` for GitHub Copilot, `GEMINI.md` for Gemini CLI, `CURSOR.md` for Cursor CLI, or `.github/cursor-instructions.md` for Cursor IDE). 6. Re-evaluate Constitution Check section → If new violations: Refactor design, return to Phase 1 → Update Progress Tracking: Post-Design Constitution Check @@ -171,7 +171,7 @@ ios/ or android/ - Quickstart test = story validation steps 5. **Update agent file incrementally** (O(1) operation): - - Run `/scripts/update-agent-context.sh [claude|gemini|copilot]` for your AI assistant + - Run `/scripts/update-agent-context.sh [claude|gemini|copilot|cursor|cursor-ide]` for your AI assistant - If exists: Add only NEW tech from current plan - Preserve manual additions between markers - Update recent changes (keep last 3) @@ -234,4 +234,4 @@ ios/ or android/ - [ ] Complexity deviations documented --- -*Based on Constitution v2.1.1 - See `/memory/constitution.md`* \ No newline at end of file +*Based on Constitution v2.1.1 - See `/memory/constitution.md`*