diff --git a/docs/compilation.md b/docs/compilation.md index df3edec4..92902094 100644 --- a/docs/compilation.md +++ b/docs/compilation.md @@ -14,14 +14,14 @@ When you run `apm compile` without specifying a target, APM automatically detect | Project Structure | Target | What Gets Generated | |-------------------|--------|---------------------| -| `.github/` folder only | `vscode` | AGENTS.md (instructions only) | +| `.github/` folder only | `copilot` | AGENTS.md (instructions only) | | `.claude/` folder only | `claude` | CLAUDE.md (instructions only) | | Both folders exist | `all` | Both AGENTS.md and CLAUDE.md | | Neither folder exists | `minimal` | AGENTS.md only (universal format) | ```bash apm compile # Auto-detects target from project structure -apm compile --target vscode # Force GitHub Copilot, Cursor, Codex, Gemini +apm compile --target copilot # Force GitHub Copilot, Cursor, Codex, Gemini apm compile --target claude # Force Claude Code, Claude Desktop ``` @@ -29,18 +29,20 @@ You can set a persistent target in `apm.yml`: ```yaml name: my-project version: 1.0.0 -target: vscode # or claude, or all +target: copilot # or vscode, claude, or all ``` ### Output Files | Target | Files Generated | Consumers | |--------|-----------------|-----------| -| `vscode` | `AGENTS.md` | GitHub Copilot, Cursor, Codex, Gemini | +| `copilot` | `AGENTS.md` | GitHub Copilot, Cursor, Codex, Gemini | | `claude` | `CLAUDE.md` | Claude Code, Claude Desktop | | `all` | Both `AGENTS.md` and `CLAUDE.md` | Universal compatibility | | `minimal` | `AGENTS.md` only | Works everywhere, no folder integration | +> **Aliases**: `vscode` and `agents` are accepted as aliases for `copilot`. + > **Note**: `AGENTS.md` and `CLAUDE.md` contain **only instructions** (grouped by `applyTo` patterns). Prompts, agents, commands, hooks, and skills are integrated by `apm install`, not `apm compile`. See the [Integrations Guide](integrations.md) for details on how `apm install` populates `.github/prompts/`, `.github/agents/`, `.github/skills/`, and `.claude/commands/`. ### How It Works diff --git a/docs/concepts.md b/docs/concepts.md index 519e8d1e..86f17e8a 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -253,7 +253,7 @@ Lifecycle event handlers that run scripts at specific points during AI operation APM generates context files for all major coding agents: -**VSCode/GitHub Target** (AGENTS.md + .github/): +**Copilot Target** (AGENTS.md + .github/): - **GitHub Copilot** - VSCode integration, chat, and CLI - **Cursor** - AI-first code editor - **Codex CLI** - OpenAI's development tool diff --git a/docs/dependencies.md b/docs/dependencies.md index 88794324..c9815cfb 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -37,7 +37,7 @@ Claude Skills are packages with a `SKILL.md` file that describe capabilities for # Install a Claude Skill apm install ComposioHQ/awesome-claude-skills/brand-guidelines -# For VSCode target: generates .github/agents/brand-guidelines.agent.md +# For copilot target: generates .github/agents/brand-guidelines.agent.md # For Claude target: keeps native SKILL.md format ``` diff --git a/docs/integrations.md b/docs/integrations.md index b936edc1..f2cdb67a 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -335,7 +335,7 @@ apm compile --target claude # Creates: CLAUDE.md (instructions only) # Generate only VSCode/Copilot formats -apm compile --target vscode +apm compile --target copilot # Creates: AGENTS.md (instructions only) ``` diff --git a/src/apm_cli/bundle/packer.py b/src/apm_cli/bundle/packer.py index f243c62c..9e53a8a7 100644 --- a/src/apm_cli/bundle/packer.py +++ b/src/apm_cli/bundle/packer.py @@ -12,8 +12,9 @@ from .lockfile_enrichment import enrich_lockfile_for_pack -# Target prefix mapping +# Target prefix mapping ("copilot" and "vscode" both map to .github/) _TARGET_PREFIXES = { + "copilot": [".github/"], "vscode": [".github/"], "claude": [".claude/"], "all": [".github/", ".claude/"], diff --git a/src/apm_cli/cli.py b/src/apm_cli/cli.py index 0c695a6a..fe44136d 100644 --- a/src/apm_cli/cli.py +++ b/src/apm_cli/cli.py @@ -3176,9 +3176,9 @@ def _recompile(self, changed_file): @click.option( "--target", "-t", - type=click.Choice(["vscode", "agents", "claude", "all"]), + type=click.Choice(["copilot", "vscode", "agents", "claude", "all"]), default=None, - help="Target platform: vscode/agents (AGENTS.md), claude (CLAUDE.md), or all. Auto-detects if not specified.", + help="Target platform: copilot (AGENTS.md + .github/), claude (CLAUDE.md), or all. 'vscode' and 'agents' are aliases for 'copilot'. Auto-detects if not specified.", ) @click.option( "--dry-run", diff --git a/src/apm_cli/commands/pack.py b/src/apm_cli/commands/pack.py index daab1aa1..ccd9f23e 100644 --- a/src/apm_cli/commands/pack.py +++ b/src/apm_cli/commands/pack.py @@ -21,9 +21,9 @@ @click.option( "--target", "-t", - type=click.Choice(["vscode", "claude", "all"]), + type=click.Choice(["copilot", "vscode", "claude", "all"]), default=None, - help="Filter files by target (default: auto-detect).", + help="Filter files by target (default: auto-detect). 'vscode' is an alias for 'copilot'.", ) @click.option("--archive", is_flag=True, default=False, help="Produce a .tar.gz archive.") @click.option( diff --git a/src/apm_cli/core/target_detection.py b/src/apm_cli/core/target_detection.py index cd7190ab..7737fdc8 100644 --- a/src/apm_cli/core/target_detection.py +++ b/src/apm_cli/core/target_detection.py @@ -8,18 +8,24 @@ 1. Explicit --target flag (always wins) 2. apm.yml target setting (top-level field) 3. Auto-detect from existing folders: - - .github/ exists AND .claude/ doesn't → vscode + - .github/ exists AND .claude/ doesn't → copilot (internal: "vscode") - .claude/ exists AND .github/ doesn't → claude - Both exist → all - Neither exists → minimal (AGENTS.md only, no folder integration) + +"copilot" is the recommended user-facing target name. "vscode" and "agents" +are accepted as aliases and map to the same internal value. """ from pathlib import Path from typing import Literal, Optional, Tuple -# Valid target values +# Valid target values (internal canonical form) TargetType = Literal["vscode", "claude", "all", "minimal"] +# User-facing target values (includes aliases accepted by CLI) +UserTargetType = Literal["copilot", "vscode", "agents", "claude", "all", "minimal"] + def detect_target( project_root: Path, @@ -40,7 +46,7 @@ def detect_target( """ # Priority 1: Explicit --target flag if explicit_target: - if explicit_target in ("vscode", "agents"): + if explicit_target in ("copilot", "vscode", "agents"): return "vscode", "explicit --target flag" elif explicit_target == "claude": return "claude", "explicit --target flag" @@ -49,7 +55,7 @@ def detect_target( # Priority 2: apm.yml target setting if config_target: - if config_target in ("vscode", "agents"): + if config_target in ("copilot", "vscode", "agents"): return "vscode", "apm.yml target" elif config_target == "claude": return "claude", "apm.yml target" @@ -122,19 +128,23 @@ def should_compile_claude_md(target: TargetType) -> bool: return target in ("claude", "all") -def get_target_description(target: TargetType) -> str: +def get_target_description(target: UserTargetType) -> str: """Get a human-readable description of what will be generated for a target. + Accepts both internal target types and user-facing aliases. + Args: - target: The target type + target: The target type (internal or user-facing alias) Returns: str: Description of output files """ + # Normalize aliases to internal value for lookup + normalized = "vscode" if target in ("copilot", "agents") else target descriptions = { "vscode": "AGENTS.md + .github/prompts/ + .github/agents/", "claude": "CLAUDE.md + .claude/commands/ + .claude/agents/ + .claude/skills/", "all": "AGENTS.md + CLAUDE.md + .github/ + .claude/", "minimal": "AGENTS.md only (create .github/ or .claude/ for full integration)", } - return descriptions.get(target, "unknown target") + return descriptions.get(normalized, "unknown target") diff --git a/tests/unit/core/test_target_detection.py b/tests/unit/core/test_target_detection.py index 3a7574ff..ca110dd6 100644 --- a/tests/unit/core/test_target_detection.py +++ b/tests/unit/core/test_target_detection.py @@ -28,6 +28,16 @@ def test_explicit_target_vscode_wins(self, tmp_path): assert target == "vscode" assert reason == "explicit --target flag" + def test_explicit_target_copilot_maps_to_vscode(self, tmp_path): + """Explicit --target copilot maps to vscode.""" + target, reason = detect_target( + project_root=tmp_path, + explicit_target="copilot", + ) + + assert target == "vscode" + assert reason == "explicit --target flag" + def test_explicit_target_agents_maps_to_vscode(self, tmp_path): """Explicit --target agents maps to vscode.""" target, reason = detect_target( @@ -60,6 +70,17 @@ def test_explicit_target_all_wins(self, tmp_path): assert target == "all" assert reason == "explicit --target flag" + def test_config_target_copilot(self, tmp_path): + """Config target copilot maps to vscode.""" + target, reason = detect_target( + project_root=tmp_path, + explicit_target=None, + config_target="copilot", + ) + + assert target == "vscode" + assert reason == "apm.yml target" + def test_config_target_vscode(self, tmp_path): """Config target vscode is used when no explicit target.""" target, reason = detect_target( @@ -228,6 +249,12 @@ def test_minimal_target(self): class TestGetTargetDescription: """Tests for get_target_description function.""" + def test_copilot_description(self): + """Description for copilot target.""" + desc = get_target_description("copilot") + assert "AGENTS.md" in desc + assert ".github/" in desc + def test_vscode_description(self): """Description for vscode target.""" desc = get_target_description("vscode")