Skip to content

Commit bba473c

Browse files
jawwad-aliclaude
andauthored
fix(integrations): cursor-agent honors executable/extra-args env overrides (#3265)
* fix(integrations): cursor-agent ignores executable/extra-args env overrides cursor-agent's build_exec_args() hardcoded self.key as argv[0] and never called _apply_extra_args_env_var(), so the documented SPECKIT_INTEGRATION_CURSOR_AGENT_EXECUTABLE (issue #2596) and SPECKIT_INTEGRATION_CURSOR_AGENT_EXTRA_ARGS (issue #2595) hooks were silently dropped — unlike every other CLI-dispatch integration (codex, devin). Route argv[0] through _resolve_executable() and apply the extra-args hook after the mandatory headless flags, mirroring the twins. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(integrations): pin extra-args insertion order for cursor-agent Per Copilot feedback: the extra-args override test only asserted the injected tokens were present, not that they land before Spec Kit's canonical --model / --output-format flags. Exercise build_exec_args with both a model and JSON output and assert the extra args are inserted before --model / --output-format (and the canonical flags stay intact and paired). Verified this fails if the _apply_extra_args_env_var call is moved after the flag extends. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 288bd67 commit bba473c

2 files changed

Lines changed: 58 additions & 1 deletion

File tree

src/specify_cli/integrations/cursor_agent/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,15 @@ def build_exec_args(
7575
either drops tool calls or exits non-zero on the first approval
7676
prompt.
7777
"""
78-
args = [self.key, "-p", "--trust", "--approve-mcps", "--force", prompt]
78+
args = [
79+
self._resolve_executable(),
80+
"-p",
81+
"--trust",
82+
"--approve-mcps",
83+
"--force",
84+
prompt,
85+
]
86+
self._apply_extra_args_env_var(args)
7987
if model:
8088
args.extend(["--model", model])
8189
if output_json:

tests/integrations/test_integration_cursor_agent.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,55 @@ def test_build_exec_args_supports_dispatch_without_requires_cli(self):
125125
assert argv is not None
126126
assert argv[0] == "cursor-agent"
127127

128+
def test_build_exec_args_honors_executable_override(self, monkeypatch):
129+
"""``SPECKIT_INTEGRATION_CURSOR_AGENT_EXECUTABLE`` overrides argv[0].
130+
131+
Every other CLI-dispatch integration (codex, devin, ...) routes
132+
argv[0] through ``_resolve_executable()`` so operators can pin a
133+
binary path (issue #2596). cursor-agent hardcoded ``self.key`` and
134+
silently ignored the documented override.
135+
"""
136+
monkeypatch.setenv(
137+
"SPECKIT_INTEGRATION_CURSOR_AGENT_EXECUTABLE", "/custom/cursor"
138+
)
139+
i = get_integration("cursor-agent")
140+
args = i.build_exec_args("/speckit-plan", output_json=False)
141+
assert args[0] == "/custom/cursor"
142+
# The mandatory headless flags must still be present.
143+
for flag in ("-p", "--trust", "--approve-mcps", "--force"):
144+
assert flag in args
145+
146+
def test_build_exec_args_honors_extra_args_override(self, monkeypatch):
147+
"""``SPECKIT_INTEGRATION_CURSOR_AGENT_EXTRA_ARGS`` flags are injected
148+
*before* Spec Kit's canonical ``--model`` / ``--output-format`` flags.
149+
150+
The ``_apply_extra_args_env_var()`` hook (issue #2595) was never
151+
invoked by cursor-agent, so operator-supplied flags were dropped.
152+
Insertion order is the real contract: extra args must land after the
153+
mandatory headless flags but before ``--model`` / ``--output-format``,
154+
so they cannot clobber, displace, or reorder Spec Kit's canonical
155+
trailing flags. Exercise with both a model and JSON output so both
156+
canonical flags are present to pin against.
157+
"""
158+
monkeypatch.setenv(
159+
"SPECKIT_INTEGRATION_CURSOR_AGENT_EXTRA_ARGS", "--foo bar"
160+
)
161+
i = get_integration("cursor-agent")
162+
args = i.build_exec_args(
163+
"/speckit-plan", model="sonnet-4-thinking", output_json=True
164+
)
165+
assert "--foo" in args
166+
assert "bar" in args
167+
# "bar" is the value of "--foo": the tokens stay adjacent and in order.
168+
assert args.index("bar") == args.index("--foo") + 1
169+
# Extra args are inserted before the canonical flags, so they cannot
170+
# clobber or reorder them (the behavioral contract this test guards).
171+
assert args.index("--foo") < args.index("--model")
172+
assert args.index("--foo") < args.index("--output-format")
173+
# The canonical flags themselves remain intact and correctly paired.
174+
assert args[args.index("--model") + 1] == "sonnet-4-thinking"
175+
assert args[args.index("--output-format") + 1] == "json"
176+
128177
def test_build_command_invocation_uses_hyphenated_skill_name(self):
129178
"""SkillsIntegration: /speckit-plan (not /speckit.plan)."""
130179
i = get_integration("cursor-agent")

0 commit comments

Comments
 (0)