From ee8574e98cbc9ac723e54807a601e39d9a11728b Mon Sep 17 00:00:00 2001 From: RaycarlLei <38275852+RaycarlLei@users.noreply.github.com> Date: Mon, 19 Oct 2026 19:19:25 -0400 Subject: [PATCH] fix(integrations): map Kimi Code JSON dispatch to --output-format stream-json KimiIntegration inherited SkillsIntegration.build_exec_args(), which appends --output-format json when output_json is true. Kimi Code CLI restricts --output-format to text and stream-json, so its option parser rejects the value and kimi exits 1 before the prompt runs. This is reachable through dispatch_command(stream=False) when output_json is left unset (it then resolves to True), and through direct build_exec_args() calls. Override build_exec_args() to request stream-json instead, keeping the base requires_cli guard and argument order (EXTRA_ARGS before --model). Assisted-by: Claude Code (model: Claude Opus 5.5, autonomous) Co-Authored-By: Claude Opus 5.5 --- src/specify_cli/integrations/kimi/__init__.py | 29 +++++++++ tests/integrations/test_integration_kimi.py | 64 +++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/src/specify_cli/integrations/kimi/__init__.py b/src/specify_cli/integrations/kimi/__init__.py index 07142db854..dafc1aed4e 100644 --- a/src/specify_cli/integrations/kimi/__init__.py +++ b/src/specify_cli/integrations/kimi/__init__.py @@ -12,6 +12,7 @@ from __future__ import annotations import shutil +from collections.abc import Mapping, Sequence from pathlib import Path from typing import Any @@ -61,6 +62,34 @@ def post_process_skill_content(self, content: str) -> str: """Ensure in-skill cross-command references use Kimi's `/skill:` syntax.""" return super().post_process_skill_content(content) + 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 ``kimi`` execution. + + ``SkillsIntegration``'s default requests ``--output-format json``, + which Kimi Code CLI does not accept: the option only allows ``text`` + and ``stream-json``, so the CLI exits 1 before the prompt runs. + Structured output maps to ``stream-json`` (JSONL events) instead. + """ + self.validate_runtime_config(integration_args, integration_options) + if not self.config or not self.config.get("requires_cli"): + return None + args = [self._resolve_executable(), "-p", prompt] + self._apply_extra_args_env_var(args) + if model: + args.extend(["--model", model]) + if output_json: + args.extend(["--output-format", "stream-json"]) + return args + @classmethod def options(cls) -> list[IntegrationOption]: return [ diff --git a/tests/integrations/test_integration_kimi.py b/tests/integrations/test_integration_kimi.py index 9e70edba7c..043b3c87b9 100644 --- a/tests/integrations/test_integration_kimi.py +++ b/tests/integrations/test_integration_kimi.py @@ -36,6 +36,70 @@ class TestKimiIntegration(SkillsIntegrationTests): COMMANDS_SUBDIR = "skills" REGISTRAR_DIR = ".kimi-code/skills" + def test_build_exec_args_uses_prompt_flag(self): + integration = get_integration("kimi") + + args = integration.build_exec_args( + "/skill:speckit-specify build a login page", + output_json=False, + ) + + assert args == ["kimi", "-p", "/skill:speckit-specify build a login page"] + + def test_build_exec_args_requests_stream_json(self): + """Kimi only accepts `text` and `stream-json`; `json` exits 1 before the prompt runs.""" + integration = get_integration("kimi") + + args = integration.build_exec_args( + "/skill:speckit-plan add OAuth", output_json=True + ) + + assert args == [ + "kimi", + "-p", + "/skill:speckit-plan add OAuth", + "--output-format", + "stream-json", + ] + assert "json" not in args + + def test_build_exec_args_forwards_model(self): + integration = get_integration("kimi") + + args = integration.build_exec_args( + "/skill:speckit-specify build a login page", + model="kimi-code/k3", + output_json=False, + ) + + assert args == [ + "kimi", + "-p", + "/skill:speckit-specify build a login page", + "--model", + "kimi-code/k3", + ] + + def test_build_exec_args_applies_extra_args(self, monkeypatch): + monkeypatch.setenv("SPECKIT_INTEGRATION_KIMI_EXTRA_ARGS", "--add-dir ../shared") + integration = get_integration("kimi") + + args = integration.build_exec_args( + "check the build", model="kimi-code/k3", output_json=True + ) + + assert args == [ + "kimi", + "-p", + "check the build", + "--add-dir", + "../shared", + "--model", + "kimi-code/k3", + "--output-format", + "stream-json", + ] + class TestKimiOptions: """Kimi declares --skills and --migrate-legacy options."""