diff --git a/adr_kit/cli.py b/adr_kit/cli.py index f40d9bd..097d9d7 100644 --- a/adr_kit/cli.py +++ b/adr_kit/cli.py @@ -831,29 +831,34 @@ def _setup_claude_impl() -> None: # Create Claude Code config claude_config = { - "servers": { + "mcpServers": { "adr-kit": { "command": adr_kit_command, "args": ["mcp-server"], - "description": "AI-first Architectural Decision Records management", - "tools": [ - "adr_init", - "adr_query_related", - "adr_create", - "adr_approve", - "adr_supersede", - "adr_validate", - "adr_index", - "adr_export_lint_config", - "adr_render_site", - ], } } } - claude_config_file = Path(".claude-mcp-config.json") + claude_config_file = Path(".mcp.json") + + # Load existing config if present to avoid clobbering other entries + existing_config = {} + if claude_config_file.exists(): + try: + with open(claude_config_file) as f: + existing_config = json.load(f) + except json.JSONDecodeError: + # Treat invalid JSON as empty config + pass + + # Merge configs: preserve existing keys, update mcpServers + if "mcpServers" in existing_config: + existing_config["mcpServers"].update(claude_config["mcpServers"]) + else: + existing_config.update(claude_config) + with open(claude_config_file, "w") as f: - json.dump(claude_config, f, indent=2) + json.dump(existing_config, f, indent=2) console.print(f"✅ Created {claude_config_file}") diff --git a/adr_kit/core/validate.py b/adr_kit/core/validate.py index a8a5747..7f42487 100644 --- a/adr_kit/core/validate.py +++ b/adr_kit/core/validate.py @@ -86,13 +86,13 @@ def __init__( def _get_default_schema_path(self) -> Path: """Get path to the bundled ADR schema.""" - # Assume schema is in the schemas/ directory relative to project root - # __file__ = .../adr-kit/adr_kit/core/validate.py - # current_dir = .../adr-kit/adr_kit/core - # project_root = .../adr-kit + # Schema lives inside the package at adr_kit/schemas/adr.schema.json + # This resolves correctly after pip install (site-packages/adr_kit/schemas/) + # __file__ = .../adr_kit/core/validate.py + # current_dir = .../adr_kit/core + # package_root = .../adr_kit current_dir = Path(__file__).parent - project_root = current_dir.parent.parent - return project_root / "schemas" / "adr.schema.json" + return current_dir.parent / "schemas" / "adr.schema.json" def _load_schema(self) -> dict[str, Any]: """Load and parse the JSON schema.""" diff --git a/schemas/adr.schema.json b/adr_kit/schemas/adr.schema.json similarity index 100% rename from schemas/adr.schema.json rename to adr_kit/schemas/adr.schema.json diff --git a/pyproject.toml b/pyproject.toml index ac247b2..02ad8af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,6 +64,9 @@ where = ["."] include = ["adr_kit*"] exclude = ["tests*", "scripts*", ".agent*"] +[tool.setuptools.package-data] +adr_kit = ["schemas/*"] + [tool.black] line-length = 88 target-version = ['py310'] diff --git a/tests/integration/test_setup_commands.py b/tests/integration/test_setup_commands.py new file mode 100644 index 0000000..74fa306 --- /dev/null +++ b/tests/integration/test_setup_commands.py @@ -0,0 +1,47 @@ +"""Integration tests for setup-claude config output and schema packaging fix.""" + +import json +from pathlib import Path + +from typer.testing import CliRunner + +from adr_kit.cli import app + +runner = CliRunner() + + +def test_setup_claude_creates_mcp_json(tmp_path): + with runner.isolated_filesystem(temp_dir=tmp_path): + result = runner.invoke(app, ["setup-claude"]) + assert Path(".mcp.json").exists(), ".mcp.json must be created by setup-claude" + assert not Path( + ".claude-mcp-config.json" + ).exists(), ".claude-mcp-config.json must not be created (wrong filename)" + + +def test_setup_claude_uses_mcp_servers_key(tmp_path): + with runner.isolated_filesystem(temp_dir=tmp_path): + runner.invoke(app, ["setup-claude"]) + config = json.loads(Path(".mcp.json").read_text()) + assert "mcpServers" in config, "top-level key must be 'mcpServers'" + assert "servers" not in config, "'servers' key must not be present" + + +def test_setup_claude_no_stale_tools_array(tmp_path): + with runner.isolated_filesystem(temp_dir=tmp_path): + runner.invoke(app, ["setup-claude"]) + config = json.loads(Path(".mcp.json").read_text()) + server = config["mcpServers"]["adr-kit"] + assert "tools" not in server, "stale tools array must be removed from config" + assert "description" not in server, "description field must be removed" + + +def test_schema_file_bundled_in_package(): + from adr_kit.core.validate import ADRValidator + + validator = ADRValidator.__new__(ADRValidator) + schema_path = validator._get_default_schema_path() + assert schema_path.exists(), ( + f"Schema must exist at {schema_path} — " + "schemas/adr.schema.json must be bundled inside adr_kit/schemas/" + ) diff --git a/tests/unit/test_adr_schema.py b/tests/unit/test_adr_schema.py index 4ab7bc3..aa24cf6 100644 --- a/tests/unit/test_adr_schema.py +++ b/tests/unit/test_adr_schema.py @@ -6,7 +6,7 @@ import jsonschema import pytest -SCHEMA_PATH = Path(__file__).parents[2] / "schemas" / "adr.schema.json" +SCHEMA_PATH = Path(__file__).parents[2] / "adr_kit" / "schemas" / "adr.schema.json" SCHEMA = json.loads(SCHEMA_PATH.read_text())