github / github/spec-kit

[Bug]: Systematic build_exec_args() audit — CLI dispatch flags unverified for 11+ integrations

オープン
#2,416 コメント 3 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
Python
スター
137k
フォーク
12.3k
平均マージ
2日 7時間
マージ済み PR(30日)
155

説明

## Scope extends beyond opencode — systematic `build_exec_args()` audit

While investigating the opencode dispatch bug, I audited **all 28 integrations** and found that the root cause is not specific to opencode — it's a systematic architectural weakness in how `build_exec_args()` is inherited.

### Current state

Only **4 out of 15 CLI-capable integrations** have verified, correct `build_exec_args()` implementations:

| Integration | Base class | CLI invocation | Status |
|---|---|---|---|
| **Claude** | `SkillsIntegration` | `claude -p "prompt" --model X --output-format json` | ✅ Verified (`-p` is documented) |
| **Gemini** | `TomlIntegration` | `gemini -p "prompt" -m X --output-format json` | ✅ Verified (`-p` and `-m` are documented) |
| **Codex** | `SkillsIntegration` | `codex exec "prompt" --model X --json` | ✅ Custom override with `exec` subcommand |
| **Copilot** | `IntegrationBase` | `copilot -p "prompt" --agent X --yolo --model X --output-format json` | ✅ Custom override with dynamic `--yolo` |

The remaining **11 integrations with `requires_cli: True`** all inherit `build_exec_args()` from their base class without verification that the CLI actually supports the generated flags:

| Integration | Inherited invocation | Risk |
|---|---|---|
| **OpenCode** | `opencode -p "prompt" --model X --output-format json` | ❌ **Confirmed broken** — should be `opencode run "prompt" -m X` |
| **Amp** | `amp -p "prompt" --model X --output-format json` | ⚠️ Unverified |
| **Auggie** | `auggie -p "prompt" --model X --output-format json` | ⚠️ Unverified |
| **CodeBuddy** | `codebuddy -p "prompt" --model X --output-format json` | ⚠️ Unverified |
| **Forge** | `forge -p "prompt" --model X --output-format json` | ⚠️ Unverified |
| **iFlow** | `iflow -p "prompt" --model X --output-format json` | ⚠️ Unverified |
| **Junie** | `junie -p "prompt" --model X --output-format json` | ⚠️ Unverified |
| **Kiro CLI** | `kiro-cli -p "prompt" --model X --output-format json` | ⚠️ Unverified |
| **Pi** | `pi -p "prompt" --model X --output-format json` | ⚠️ Unverified |
| **QoderCLI** | `qodercli -p "prompt" --model X --output-format json` | ⚠️ Unverified |
| **Qwen** | `qwen -p "prompt" --model X --output-format json` | ⚠️ Unverified |

Additionally, **3 SkillsIntegration-based CLIs** (Kimi, Shai, Vibe) and **1 TomlIntegration-based CLI** (Tabnine) inherit the same `-p` pattern without verification.

There's also a data inconsistency: **Goose** has `requires_cli: True` but inherits from `YamlIntegration`, which doesn't override `build_exec_args()` — so it returns `None`, meaning CLI dispatch silently fails despite claiming CLI support.

### Root cause

`MarkdownIntegration.build_exec_args()` hardcodes three assumptions that don't hold for all CLIs:

1. **Prompt mechanism**: `-p` flag (works for Claude/Gemini) vs. `run`/`exec` subcommand (opencode/codex) vs. other formats
2. **Model flag**: `--model` long form (most) vs. `-m` short form (Gemini, opencode) vs. not supported
3. **JSON output**: `--output-format json` (most) vs. `--json` (Codex) vs. `-f json` (opencode) vs. not supported

Every deviation requires a full method override, which is easy to forget (as the opencode bug shows).

### Proposed fix: Declarative batch-mode attributes

Instead of requiring each integration to override `build_exec_args()`, introduce class-level attributes on `IntegrationBase` that make the common variations declarative:

```python
class IntegrationBase(ABC):
exec_mode: str = "flag" # "flag" | "subcommand" | "none"
exec_prompt_flag: str = "-p" # flag used when exec_mode="flag"
exec_subcommand: str = "" # subcommand when exec_mode="subcommand"
exec_model_flag: str = "--model" # "--model" or "-m"
exec_json_args: tuple[str, ...] = ("--output-format", "json") # or ("--json",) or ()
```

Then `build_exec_args()` on `IntegrationBase` uses these attributes, and most integrations need zero method overrides:

```python
# OpencodeIntegration — just attributes, no method override
class OpencodeIntegration(MarkdownIntegration):
key = "opencode"
exec_mode = "subcommand"
exec_subcommand = "run"
exec_model_flag = "-m"
exec_json_args = ()
...

# CodexIntegration — just attributes, no method override
class CodexIntegration(SkillsIntegration):
key = "codex"
exec_mode = "subcommand"
exec_subcommand = "exec"
exec_json_args = ("--json",)
...
```

Complex cases like Copilot (dynamic `--yolo` flag) still override `build_exec_args()` directly.

This makes CLI invocation patterns **visible at a glance** in the integration class, eliminates an entire class of bugs, and reduces boilerplate from ~15 lines per override to ~4 lines of attributes.

---

*Originally posted as a comment on [#2409](https://github.com/github/spec-kit/issues/2409#issuecomment-4344752659)*

コントリビューションガイド

コントリビューションガイドを開く

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。