diff --git a/src/specify_cli/_invocation_style.py b/src/specify_cli/_invocation_style.py index 5cc7098837..ec6ac0f323 100644 --- a/src/specify_cli/_invocation_style.py +++ b/src/specify_cli/_invocation_style.py @@ -12,7 +12,9 @@ DOLLAR_SKILLS_AGENTS: frozenset[str] = frozenset({"codex", "zcode", "command-code"}) # Agents that always render /speckit-, regardless of ai_skills. -ALWAYS_SLASH_AGENTS: frozenset[str] = frozenset({"devin", "droid", "grok", "trae", "zed"}) +ALWAYS_SLASH_AGENTS: frozenset[str] = frozenset( + {"devin", "droid", "grok", "qodercli", "trae", "zed"} +) # Agents that render /speckit- only when ai_skills is enabled. CONDITIONAL_SLASH_AGENTS: frozenset[str] = frozenset( diff --git a/src/specify_cli/integrations/qodercli/__init__.py b/src/specify_cli/integrations/qodercli/__init__.py index 13535203cf..57b6261f3e 100644 --- a/src/specify_cli/integrations/qodercli/__init__.py +++ b/src/specify_cli/integrations/qodercli/__init__.py @@ -1,21 +1,26 @@ -"""Qoder CLI integration.""" +"""Qoder CLI integration. -from ..base import MarkdownIntegration +Qoder IDE 1.24+ dropped ``.qoder/commands/`` scanning in favour of the +skills layout: ``.qoder/skills/{skill-name}/SKILL.md`` with a ``name`` +field in frontmatter. Migrated to ``SkillsIntegration`` to match. +""" +from ..base import SkillsIntegration -class QodercliIntegration(MarkdownIntegration): + +class QodercliIntegration(SkillsIntegration): key = "qodercli" config = { "name": "Qoder CLI", "folder": ".qoder/", - "commands_subdir": "commands", + "commands_subdir": "skills", "install_url": "https://qoder.com/cli", "requires_cli": True, } registrar_config = { - "dir": ".qoder/commands", + "dir": ".qoder/skills", "format": "markdown", "args": "$ARGUMENTS", - "extension": ".md", + "extension": "/SKILL.md", } multi_install_safe = True diff --git a/tests/integrations/test_integration_qodercli.py b/tests/integrations/test_integration_qodercli.py index 29a6d16d29..f30f62cae0 100644 --- a/tests/integrations/test_integration_qodercli.py +++ b/tests/integrations/test_integration_qodercli.py @@ -1,10 +1,39 @@ """Tests for QodercliIntegration.""" -from .test_integration_base_markdown import MarkdownIntegrationTests +import pytest +from specify_cli.integrations import get_integration -class TestQodercliIntegration(MarkdownIntegrationTests): +from .test_integration_base_skills import SkillsIntegrationTests + + +class TestQodercliIntegration(SkillsIntegrationTests): KEY = "qodercli" FOLDER = ".qoder/" - COMMANDS_SUBDIR = "commands" - REGISTRAR_DIR = ".qoder/commands" + COMMANDS_SUBDIR = "skills" + REGISTRAR_DIR = ".qoder/skills" + + def test_options_include_skills_flag(self): + """Not applicable — Qoder IDE 1.24+ is always skills-based.""" + pytest.skip( + "Qoder is always skills-based and does not expose a --skills option" + ) + + def test_options_do_not_include_skills_flag(self): + """Qoder is always skills-based; no --skills option is exposed.""" + i = get_integration(self.KEY) + assert i is not None + opts = i.options() + skills_opts = [o for o in opts if o.name == "--skills"] + assert len(skills_opts) == 0, ( + "Qoder is always skills-based and should not expose a --skills option" + ) + + def test_requires_cli_is_true(self): + """Qoder CLI is a CLI-based agent; requires_cli must remain True.""" + i = get_integration(self.KEY) + assert i is not None + assert i.config is not None + assert i.config["requires_cli"] is True + assert i.config["name"] == "Qoder CLI" + assert i.multi_install_safe is True