diff --git a/docs/integrations/pi.md b/docs/integrations/pi.md index 92dad03b8f..4e3d2ce7f4 100644 --- a/docs/integrations/pi.md +++ b/docs/integrations/pi.md @@ -26,7 +26,8 @@ Invoke them in the agent's chat using dotted notation, for example ## Workflow Dispatch and Tooling Workflow steps use `pi -p `, with `--model` when configured and -`--output-format json` when structured output is requested. +`--mode json` (JSONL events), not `--output-format`, when structured output is +requested. There are no integration-specific setup options. This integration scaffolds prompt files; it does not install or configure MCP diff --git a/src/specify_cli/integrations/pi/__init__.py b/src/specify_cli/integrations/pi/__init__.py index a43ee0c75f..66e9059a9f 100644 --- a/src/specify_cli/integrations/pi/__init__.py +++ b/src/specify_cli/integrations/pi/__init__.py @@ -1,5 +1,11 @@ """Pi Coding Agent integration.""" +from __future__ import annotations + +from collections.abc import Mapping, Sequence +from pathlib import Path +from typing import Any + from ..base import MarkdownIntegration @@ -19,3 +25,31 @@ class PiIntegration(MarkdownIntegration): "extension": ".md", } multi_install_safe = True + + 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 ``pi`` execution. + + ``MarkdownIntegration``'s default requests ``--output-format json``, + which Pi does not define: it rejects the unknown option and exits 1 + before the prompt runs. Pi selects JSONL events with ``--mode json``, + the same flag the OMP integration already passes. + """ + 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(["--mode", "json"]) + return args diff --git a/tests/integrations/test_integration_pi.py b/tests/integrations/test_integration_pi.py index 620dd1f598..bb63b87c63 100644 --- a/tests/integrations/test_integration_pi.py +++ b/tests/integrations/test_integration_pi.py @@ -16,3 +16,59 @@ def test_multi_install_safe(self): # every other integration, so it must be co-install safe (mirrors # qwen/shai/qodercli and the kiro-cli #3471 precedent). assert get_integration(self.KEY).multi_install_safe is True + + def test_build_exec_args_uses_prompt_flag(self): + integration = get_integration(self.KEY) + + args = integration.build_exec_args( + "/speckit.specify build a login page", + output_json=False, + ) + + assert args == ["pi", "-p", "/speckit.specify build a login page"] + + def test_build_exec_args_requests_json_mode(self): + """Pi has no `--output-format`; JSONL events are selected with `--mode json`.""" + integration = get_integration(self.KEY) + + args = integration.build_exec_args("/speckit.plan add OAuth", output_json=True) + + assert args == ["pi", "-p", "/speckit.plan add OAuth", "--mode", "json"] + assert "--output-format" not in args + + def test_build_exec_args_forwards_model(self): + integration = get_integration(self.KEY) + + args = integration.build_exec_args( + "/speckit.specify build a login page", + model="openai/gpt-4o", + output_json=False, + ) + + assert args == [ + "pi", + "-p", + "/speckit.specify build a login page", + "--model", + "openai/gpt-4o", + ] + + def test_build_exec_args_applies_extra_args(self, monkeypatch): + monkeypatch.setenv("SPECKIT_INTEGRATION_PI_EXTRA_ARGS", "--thinking high") + integration = get_integration(self.KEY) + + args = integration.build_exec_args( + "check the build", model="openai/gpt-4o", output_json=True + ) + + assert args == [ + "pi", + "-p", + "check the build", + "--thinking", + "high", + "--model", + "openai/gpt-4o", + "--mode", + "json", + ]