Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/specify_cli/integrations/zcode/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

from __future__ import annotations

from collections.abc import Mapping, Sequence
from pathlib import Path
from typing import Any

from ..base import IntegrationOption, SkillsIntegration


Expand Down Expand Up @@ -40,3 +44,29 @@ def options(cls) -> list[IntegrationOption]:
help="Install as agent skills (default for ZCode)",
),
]

def build_exec_args(
self,
prompt: str,
*,
model: str | None = None,
output_json: bool = True,
integration_args: Sequence[str] | None = None,
integration_options: Mapping[str, Any] | None = None,
project_root: Path | None = None,
) -> list[str] | None:
"""Build CLI arguments for non-interactive ``zcode`` execution.

``SkillsIntegration``'s default appends ``--model``, which the ZCode
CLI does not define. Its argument parser is strict, so a dispatched
step exits 1 with ``Unknown option '--model'`` whenever a ``model``
is configured. ``model`` is deliberately dropped: ZCode has no
per-invocation model flag and switches models in-session with
``/model``. ``-p`` and ``--output-format json`` are both valid.
"""
self.validate_runtime_config(integration_args, integration_options)
args = [self._resolve_executable(), "-p", prompt]
self._apply_extra_args_env_var(args)
if output_json:
args.extend(["--output-format", "json"])
return args
57 changes: 57 additions & 0 deletions tests/integrations/test_integration_zcode.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Tests for ZcodeIntegration — skills-based integration (Z.AI)."""

from specify_cli.integrations import get_integration

from .test_integration_base_skills import SkillsIntegrationTests


Expand All @@ -9,6 +11,61 @@ class TestZcodeIntegration(SkillsIntegrationTests):
COMMANDS_SUBDIR = "skills"
REGISTRAR_DIR = ".zcode/skills"

def test_build_exec_args_uses_prompt_flag(self):
integration = get_integration("zcode")

args = integration.build_exec_args(
"$speckit-specify build a login page",
output_json=False,
)

assert args == ["zcode", "-p", "$speckit-specify build a login page"]

def test_build_exec_args_requests_json_output(self):
integration = get_integration("zcode")

args = integration.build_exec_args("$speckit-plan add OAuth", output_json=True)

assert args == [
"zcode",
"-p",
"$speckit-plan add OAuth",
"--output-format",
"json",
]

def test_build_exec_args_omits_model_flag(self):
"""ZCode has no model flag; its strict parser rejects `--model` and exits 1."""
integration = get_integration("zcode")

args = integration.build_exec_args(
"$speckit-specify build a login page",
model="glm-5",
output_json=False,
)

assert args == ["zcode", "-p", "$speckit-specify build a login page"]
assert "--model" not in args
assert "glm-5" not in args

def test_build_exec_args_applies_extra_args(self, monkeypatch):
monkeypatch.setenv("SPECKIT_INTEGRATION_ZCODE_EXTRA_ARGS", "--mode build")
integration = get_integration("zcode")

args = integration.build_exec_args(
"check the build", model="glm-5", output_json=True
)

assert args == [
"zcode",
"-p",
"check the build",
"--mode",
"build",
"--output-format",
"json",
]

class TestZcodeInvocation:
"""ZCode renders $speckit-* chat invocations (like Codex)."""

Expand Down