From 05a18f9d9a50c0009c44c02402a3b22357e62bc0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:13:33 +0000 Subject: [PATCH 1/2] Fix qodercli-skills-migration: migrate QodercliIntegration to SkillsIntegration Apply the remediation from the bug assessment on issue #4199. Qoder IDE 1.24+ dropped .qoder/commands/ scanning in favour of the skills layout (.qoder/skills/{skill-name}/SKILL.md). Migrated QodercliIntegration from MarkdownIntegration to SkillsIntegration, updating config[commands_subdir] to 'skills' and registrar_config[dir] to '.qoder/skills' with extension '/SKILL.md'. Updated tests to use SkillsIntegrationTests base mixin. Refs #4199 Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../integrations/qodercli/__init__.py | 17 +++++++++++------ tests/integrations/test_integration_qodercli.py | 8 ++++---- 2 files changed, 15 insertions(+), 10 deletions(-) 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..02dc97d8b4 100644 --- a/tests/integrations/test_integration_qodercli.py +++ b/tests/integrations/test_integration_qodercli.py @@ -1,10 +1,10 @@ """Tests for QodercliIntegration.""" -from .test_integration_base_markdown import MarkdownIntegrationTests +from .test_integration_base_skills import SkillsIntegrationTests -class TestQodercliIntegration(MarkdownIntegrationTests): +class TestQodercliIntegration(SkillsIntegrationTests): KEY = "qodercli" FOLDER = ".qoder/" - COMMANDS_SUBDIR = "commands" - REGISTRAR_DIR = ".qoder/commands" + COMMANDS_SUBDIR = "skills" + REGISTRAR_DIR = ".qoder/skills" From 7edf7c239b1d2f81ac32a0c745395cea9e485920 Mon Sep 17 00:00:00 2001 From: Manfred Riem <15701806+mnriem@users.noreply.github.com> Date: Wed, 19 Aug 2026 17:00:48 -0500 Subject: [PATCH 2/2] fix(qodercli): resolve failing skills-flag test and slash invocation Builds on the qodercli->SkillsIntegration migration (PR #4205). Qoder IDE 1.24+ is always skills-based, so it should not expose a --skills toggle. Override the inherited SkillsIntegrationTests.test_options_include_skills_flag to skip (mirroring Grok/Zed/Droid) and add a test asserting no --skills option, plus a requires_cli/name/multi_install_safe check. Also add "qodercli" to ALWAYS_SLASH_AGENTS so hooks and next-steps render the hyphenated /speckit- invocation instead of the legacy dotted /speckit. form. Fixes the single failing test reported for #4199. Assisted-by: GitHub Copilot (model: claude-opus-4.8, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 43394151-ce2a-432d-9cc5-88f587d1b570 --- src/specify_cli/_invocation_style.py | 4 ++- .../integrations/test_integration_qodercli.py | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) 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/tests/integrations/test_integration_qodercli.py b/tests/integrations/test_integration_qodercli.py index 02dc97d8b4..f30f62cae0 100644 --- a/tests/integrations/test_integration_qodercli.py +++ b/tests/integrations/test_integration_qodercli.py @@ -1,5 +1,9 @@ """Tests for QodercliIntegration.""" +import pytest + +from specify_cli.integrations import get_integration + from .test_integration_base_skills import SkillsIntegrationTests @@ -8,3 +12,28 @@ class TestQodercliIntegration(SkillsIntegrationTests): FOLDER = ".qoder/" 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