From 18f8e98fe13be95258cb96d9536407d99243c45c Mon Sep 17 00:00:00 2001 From: jawwad-ali Date: Tue, 14 Jul 2026 23:12:44 +0500 Subject: [PATCH] fix(integrations): Forge dispatches hyphenated /speckit- invocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Forge installs its slash-commands with hyphenated names (speckit-foo-bar, via format_forge_command_name and the injected frontmatter name), but ForgeIntegration inherited MarkdownIntegration.build_command_invocation, which builds the dotted /speckit.. So 'workflow'/command dispatch invoked /speckit.plan while the registered command is /speckit-plan — a name Forge never registered. Override build_command_invocation to reuse format_forge_command_name, producing /speckit- (with '.'-to-'-' for extension commands), mirroring the skills agents' hyphenated invocation. Tests assert Forge core + extension invocations are hyphenated, incl. args (fail before: dotted /speckit.plan / /speckit.git.commit). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/specify_cli/integrations/forge/__init__.py | 12 ++++++++++++ tests/integrations/test_base.py | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/specify_cli/integrations/forge/__init__.py b/src/specify_cli/integrations/forge/__init__.py index 49407c3a7a..f455556e36 100644 --- a/src/specify_cli/integrations/forge/__init__.py +++ b/src/specify_cli/integrations/forge/__init__.py @@ -91,6 +91,18 @@ class ForgeIntegration(MarkdownIntegration): } invoke_separator = "-" + def build_command_invocation(self, command_name: str, args: str = "") -> str: + """Forge installs hyphenated slash-commands (``/speckit-``), so the + dispatch invocation must match. The inherited MarkdownIntegration default + builds the dotted ``/speckit.``, which references a command Forge + never registered. Reuse the same hyphenation as the installed frontmatter + ``name`` (see ``format_forge_command_name``), mirroring the skills agents. + """ + invocation = "/" + format_forge_command_name(command_name) + if args: + invocation = f"{invocation} {args}" + return invocation + def setup( self, project_root: Path, diff --git a/tests/integrations/test_base.py b/tests/integrations/test_base.py index d03ea0cb25..6e6229ba3c 100644 --- a/tests/integrations/test_base.py +++ b/tests/integrations/test_base.py @@ -216,6 +216,24 @@ def test_skills_extension_command_with_args(self): i = get_integration("codex") assert i.build_command_invocation("speckit.git.commit", "fix typo") == "/speckit-git-commit fix typo" + def test_forge_core_command_hyphenated(self): + """Forge installs hyphenated slash-commands (/speckit-), so the + dispatch invocation must be hyphenated too — not the dotted default it + would inherit from MarkdownIntegration.""" + from specify_cli.integrations import get_integration + i = get_integration("forge") + assert i.build_command_invocation("speckit.plan") == "/speckit-plan" + assert i.build_command_invocation("plan") == "/speckit-plan" + + def test_forge_extension_command_hyphenated(self): + from specify_cli.integrations import get_integration + i = get_integration("forge") + assert i.build_command_invocation("speckit.git.commit") == "/speckit-git-commit" + assert ( + i.build_command_invocation("speckit.git.commit", "fix typo") + == "/speckit-git-commit fix typo" + ) + class TestResolveCommandRefs: """Tests for __SPECKIT_COMMAND___ placeholder resolution."""