mirror of
https://github.com/github/spec-kit.git
synced 2026-08-03 06:26:30 +08:00
* fix(integrations): render hyphenated /speckit-<name> for Droid (always-slash agent)
DroidIntegration is an always-skills agent: it installs commands as
.factory/skills/speckit-<name>/SKILL.md and its build_command_invocation
returns the hyphenated /speckit-<name>. But "droid" was missing from every
_invocation_style set, so is_slash_skills_agent("droid", True) returned False
and both HookExecutor._render_hook_invocation and `specify init` next-steps
fell through to the dotted /speckit.<name> form — a command Droid never
registers.
Add "droid" to ALWAYS_SLASH_AGENTS, matching its always-skills siblings
grok/trae/zed/devin (each added there by their own integration PR; droid's
#3587 omitted it).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(integrations): assert Droid is ALWAYS-slash (disabled case too)
Address review: the test only covered ai_skills=True, which would also pass
if Droid were miscategorized as CONDITIONAL_SLASH. Add the ai_skills=False
assertion — True there is what distinguishes an ALWAYS_SLASH agent from a
conditional one.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
79 lines
2.8 KiB
Python
79 lines
2.8 KiB
Python
"""Agent invocation-style constants and helpers.
|
|
|
|
Agents that scaffold skills (``speckit-<name>/SKILL.md``) use different
|
|
slash-command invocation formats depending on the agent. This module
|
|
centralises the mapping so that ``HookExecutor._render_hook_invocation``
|
|
and ``specify init``'s next-steps output stay consistent.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
# Agents that render $speckit-<name> (chat invocation) when in skills mode.
|
|
DOLLAR_SKILLS_AGENTS: frozenset[str] = frozenset({"codex", "zcode"})
|
|
|
|
# Agents that always render /speckit-<name>, regardless of ai_skills.
|
|
ALWAYS_SLASH_AGENTS: frozenset[str] = frozenset({"devin", "droid", "grok", "trae", "zed"})
|
|
|
|
# Agents that render /speckit-<name> only when ai_skills is enabled.
|
|
CONDITIONAL_SLASH_AGENTS: frozenset[str] = frozenset(
|
|
{
|
|
"agy",
|
|
"bob",
|
|
"claude",
|
|
"copilot",
|
|
"cursor-agent",
|
|
"hermes",
|
|
"lingma",
|
|
"rovodev",
|
|
"vibe",
|
|
}
|
|
)
|
|
|
|
# Agents that render /skill:<name> (skill-colon invocation) when in skills mode.
|
|
SKILL_COLON_AGENTS: frozenset[str] = frozenset({"kimi"})
|
|
|
|
|
|
def is_dollar_skills_agent(selected_ai: str | None, ai_skills_enabled: bool) -> bool:
|
|
"""Return ``True`` if *selected_ai* uses ``$speckit-<name>`` invocations.
|
|
|
|
Agents in `DOLLAR_SKILLS_AGENTS` (e.g. ``codex``, ``zcode``) render
|
|
``$speckit-<name>`` chat invocations when installed in skills mode.
|
|
"""
|
|
if not isinstance(selected_ai, str):
|
|
return False
|
|
return selected_ai in DOLLAR_SKILLS_AGENTS and ai_skills_enabled
|
|
|
|
|
|
def get_invocation_prefix(selected_ai: str | None, ai_skills_enabled: bool) -> str:
|
|
"""Return the native invocation prefix for *selected_ai* in skills mode.
|
|
|
|
Returns ``"$"`` for dollar-skills agents (Codex, ZCode),
|
|
``"/skill:"`` for skill-colon agents (Kimi), and ``"/"`` for all others.
|
|
"""
|
|
if not isinstance(selected_ai, str):
|
|
return "/"
|
|
if selected_ai in DOLLAR_SKILLS_AGENTS and ai_skills_enabled:
|
|
return "$"
|
|
if selected_ai in SKILL_COLON_AGENTS and ai_skills_enabled:
|
|
return "/skill:"
|
|
return "/"
|
|
|
|
|
|
def is_slash_skills_agent(selected_ai: str | None, ai_skills_enabled: bool) -> bool:
|
|
"""Return ``True`` if *selected_ai* uses ``/speckit-<name>`` invocations.
|
|
|
|
The decision is based on the agent sets defined in this module:
|
|
|
|
* Agents in `ALWAYS_SLASH_AGENTS` always use slash invocations.
|
|
* Agents in `CONDITIONAL_SLASH_AGENTS` only use them when
|
|
*ai_skills_enabled* is ``True``.
|
|
* All other agents return ``False``.
|
|
"""
|
|
if selected_ai is None:
|
|
return False
|
|
if not isinstance(selected_ai, str):
|
|
return False
|
|
return selected_ai in ALWAYS_SLASH_AGENTS or (
|
|
selected_ai in CONDITIONAL_SLASH_AGENTS and ai_skills_enabled
|
|
)
|