-
Notifications
You must be signed in to change notification settings - Fork 7.8k
feat(copilot): support --integration-options="--skills" for skills-based scaffolding
#2324
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
base: main
Are you sure you want to change the base?
Changes from 3 commits
c59e302
d12ba9b
17fdc9a
5922707
5938c22
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 | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,10 @@ | |||||||||
| - Each command gets a companion ``.prompt.md`` file in ``.github/prompts/`` | ||||||||||
| - Installs ``.vscode/settings.json`` with prompt file recommendations | ||||||||||
| - Context file lives at ``.github/copilot-instructions.md`` | ||||||||||
|
|
||||||||||
| When ``--skills`` is passed via ``--integration-options``, Copilot scaffolds | ||||||||||
| commands as ``speckit-<name>/SKILL.md`` directories under ``.github/skills/`` | ||||||||||
| instead. The two modes are mutually exclusive. | ||||||||||
| """ | ||||||||||
|
|
||||||||||
| from __future__ import annotations | ||||||||||
|
|
@@ -16,7 +20,7 @@ | |||||||||
| from pathlib import Path | ||||||||||
| from typing import Any | ||||||||||
|
|
||||||||||
| from ..base import IntegrationBase | ||||||||||
| from ..base import IntegrationBase, IntegrationOption, SkillsIntegration | ||||||||||
| from ..manifest import IntegrationManifest | ||||||||||
|
|
||||||||||
|
|
||||||||||
|
|
@@ -44,12 +48,40 @@ def _allow_all() -> bool: | |||||||||
| return True | ||||||||||
|
|
||||||||||
|
|
||||||||||
| class _CopilotSkillsHelper(SkillsIntegration): | ||||||||||
| """Internal helper used when Copilot is scaffolded in skills mode. | ||||||||||
|
|
||||||||||
| Not registered in the integration registry — only used as a delegate | ||||||||||
| by ``CopilotIntegration`` when ``--skills`` is passed. | ||||||||||
| """ | ||||||||||
|
|
||||||||||
| key = "copilot" | ||||||||||
| config = { | ||||||||||
| "name": "GitHub Copilot", | ||||||||||
| "folder": ".github/", | ||||||||||
| "commands_subdir": "skills", | ||||||||||
| "install_url": "https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-copilot-cli", | ||||||||||
| "requires_cli": False, | ||||||||||
| } | ||||||||||
| registrar_config = { | ||||||||||
| "dir": ".github/skills", | ||||||||||
| "format": "markdown", | ||||||||||
| "args": "$ARGUMENTS", | ||||||||||
| "extension": "/SKILL.md", | ||||||||||
| } | ||||||||||
| context_file = ".github/copilot-instructions.md" | ||||||||||
|
|
||||||||||
|
|
||||||||||
| class CopilotIntegration(IntegrationBase): | ||||||||||
| """Integration for GitHub Copilot (VS Code IDE + CLI). | ||||||||||
|
|
||||||||||
| The IDE integration (``requires_cli: False``) installs ``.agent.md`` | ||||||||||
| command files. Workflow dispatch additionally requires the | ||||||||||
| ``copilot`` CLI to be installed separately. | ||||||||||
|
|
||||||||||
| When ``--skills`` is passed via ``--integration-options``, commands | ||||||||||
| are scaffolded as ``speckit-<name>/SKILL.md`` under ``.github/skills/`` | ||||||||||
| instead of the default ``.agent.md`` + ``.prompt.md`` layout. | ||||||||||
| """ | ||||||||||
|
|
||||||||||
| key = "copilot" | ||||||||||
|
|
@@ -68,6 +100,20 @@ class CopilotIntegration(IntegrationBase): | |||||||||
| } | ||||||||||
| context_file = ".github/copilot-instructions.md" | ||||||||||
|
|
||||||||||
| # Mutable flag set by setup() — indicates the active scaffolding mode. | ||||||||||
| _skills_mode: bool = False | ||||||||||
|
|
||||||||||
| @classmethod | ||||||||||
| def options(cls) -> list[IntegrationOption]: | ||||||||||
| return [ | ||||||||||
| IntegrationOption( | ||||||||||
| "--skills", | ||||||||||
| is_flag=True, | ||||||||||
| default=False, | ||||||||||
| help="Scaffold commands as agent skills (speckit-<name>/SKILL.md) instead of .agent.md files", | ||||||||||
| ), | ||||||||||
| ] | ||||||||||
|
|
||||||||||
| def build_exec_args( | ||||||||||
| self, | ||||||||||
| prompt: str, | ||||||||||
|
|
@@ -92,7 +138,19 @@ def build_exec_args( | |||||||||
| return args | ||||||||||
|
|
||||||||||
| def build_command_invocation(self, command_name: str, args: str = "") -> str: | ||||||||||
| """Copilot agents are not slash-commands — just return the args as prompt.""" | ||||||||||
| """Build the native invocation for a Copilot command. | ||||||||||
|
|
||||||||||
| Default mode: agents are not slash-commands — return args as prompt. | ||||||||||
| Skills mode: ``/speckit-<stem>`` slash-command dispatch. | ||||||||||
| """ | ||||||||||
| if self._skills_mode: | ||||||||||
| stem = command_name | ||||||||||
| if "." in stem: | ||||||||||
| stem = stem.rsplit(".", 1)[-1] | ||||||||||
| invocation = f"/speckit-{stem}" | ||||||||||
| if args: | ||||||||||
| invocation = f"{invocation} {args}" | ||||||||||
| return invocation | ||||||||||
| return args or "" | ||||||||||
|
|
||||||||||
| def dispatch_command( | ||||||||||
|
|
@@ -110,19 +168,32 @@ def dispatch_command( | |||||||||
| Copilot ``.agent.md`` files are agents, not skills. The CLI | ||||||||||
| selects them with ``--agent <name>`` and the prompt is just | ||||||||||
| the user's arguments. | ||||||||||
|
|
||||||||||
| In skills mode, the prompt includes the skill invocation | ||||||||||
| (``/speckit-<stem>``). | ||||||||||
| """ | ||||||||||
| import subprocess | ||||||||||
|
|
||||||||||
| stem = command_name | ||||||||||
| if "." in stem: | ||||||||||
| stem = stem.rsplit(".", 1)[-1] | ||||||||||
| agent_name = f"speckit.{stem}" | ||||||||||
|
|
||||||||||
| prompt = args or "" | ||||||||||
| cli_args = [ | ||||||||||
| "copilot", "-p", prompt, | ||||||||||
| "--agent", agent_name, | ||||||||||
| ] | ||||||||||
| # Detect skills mode from project layout when not set via setup() | ||||||||||
| skills_mode = self._skills_mode | ||||||||||
| if not skills_mode and project_root: | ||||||||||
| skills_dir = project_root / ".github" / "skills" | ||||||||||
| if skills_dir.is_dir() and any(skills_dir.iterdir()): | ||||||||||
| skills_mode = True | ||||||||||
|
mnriem marked this conversation as resolved.
Outdated
|
||||||||||
|
|
||||||||||
| if skills_mode: | ||||||||||
| prompt = self.build_command_invocation(command_name, args) | ||||||||||
|
||||||||||
| prompt = self.build_command_invocation(command_name, args) | |
| prompt = f"/speckit-{stem}" | |
| if args: | |
| prompt = f"{prompt} {args}" |
Uh oh!
There was an error while loading. Please reload this page.