diff --git a/src/claude_agent_sdk/_internal/transport/subprocess_cli.py b/src/claude_agent_sdk/_internal/transport/subprocess_cli.py index a8bf65de..595620ad 100644 --- a/src/claude_agent_sdk/_internal/transport/subprocess_cli.py +++ b/src/claude_agent_sdk/_internal/transport/subprocess_cli.py @@ -108,6 +108,17 @@ def _find_bundled_cli(self) -> str | None: return None + def _resolve_settings_path(self, path_str: str) -> Path: + """Resolve a settings file path. + + Relative paths are resolved against `options.cwd` when provided to keep + behavior consistent with how the CLI itself resolves paths. + """ + path = Path(path_str).expanduser() + if not path.is_absolute() and self._cwd: + path = Path(self._cwd) / path + return path + def _build_settings_value(self) -> str | None: """Build settings value, merging sandbox settings if provided. @@ -143,13 +154,13 @@ def _build_settings_value(self) -> str | None: f"Failed to parse settings as JSON, treating as file path: {settings_str}" ) # Read the file - settings_path = Path(settings_str) + settings_path = self._resolve_settings_path(settings_str) if settings_path.exists(): with settings_path.open(encoding="utf-8") as f: settings_obj = json.load(f) else: # It's a file path - read and parse - settings_path = Path(settings_str) + settings_path = self._resolve_settings_path(settings_str) if settings_path.exists(): with settings_path.open(encoding="utf-8") as f: settings_obj = json.load(f) diff --git a/tests/test_transport.py b/tests/test_transport.py index 13657e0e..ef74685d 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -844,6 +844,33 @@ def test_build_command_with_sandbox_and_settings_json(self): assert parsed["sandbox"]["enabled"] is True assert parsed["sandbox"]["excludedCommands"] == ["git", "docker"] + def test_build_command_with_sandbox_and_relative_settings_file_uses_cwd( + self, tmp_path + ): + """Test sandbox+settings resolves relative paths against cwd before merging.""" + import json + + settings_path = tmp_path / "settings.json" + settings_path.write_text( + json.dumps({"permissions": {"allow": ["Read"]}}), encoding="utf-8" + ) + + transport = SubprocessCLITransport( + prompt="test", + options=make_options( + cwd=tmp_path, + settings="settings.json", + sandbox={"enabled": True}, + ), + ) + + cmd = transport._build_command() + settings_idx = cmd.index("--settings") + merged = json.loads(cmd[settings_idx + 1]) + + assert merged["permissions"] == {"allow": ["Read"]} + assert merged["sandbox"] == {"enabled": True} + def test_build_command_with_settings_file_and_no_sandbox(self): """Test that settings file path is passed through when no sandbox.""" transport = SubprocessCLITransport(