Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 29 additions & 15 deletions packages/claude-code-plugin/hooks/lib/health_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,27 +176,41 @@ def check_events_dir(self) -> Dict[str, str]:
# Check 8: MCP connection
# ------------------------------------------------------------------
def check_mcp_connection(self) -> Dict[str, str]:
"""Check if CodingBuddy MCP server is configured in mcp.json."""
mcp_json = os.path.join(self._claude_dir, "mcp.json")
if not os.path.isfile(mcp_json):
return _result("mcp_connection", "WARN", "mcp.json not found — standalone mode")
try:
with open(mcp_json, "r", encoding="utf-8") as f:
data = json.load(f)
servers = data.get("mcpServers", {})
for key in servers:
if "codingbuddy" in key.lower():
return _result("mcp_connection", "PASS", "MCP configured (codingbuddy entry found)")
return _result("mcp_connection", "WARN", "MCP not configured — standalone mode active")
except (json.JSONDecodeError, OSError):
return _result("mcp_connection", "WARN", "mcp.json unreadable — standalone mode")
"""Check if CodingBuddy MCP server is configured.

Checks three locations in order:
1. ~/.claude/mcp.json
2. ~/.claude/settings.json → mcpServers
3. {project_dir}/.mcp.json
"""
locations = [
os.path.join(self._claude_dir, "mcp.json"),
os.path.join(self._claude_dir, "settings.json"),
os.path.join(self._project_dir, ".mcp.json"),
]
for path in locations:
if not os.path.isfile(path):
continue
try:
with open(path, "r", encoding="utf-8") as f:
data = json.load(f)
servers = data.get("mcpServers", {})
for key in servers:
if "codingbuddy" in key.lower():
return _result(
"mcp_connection", "PASS",
f"MCP configured (codingbuddy entry found in {os.path.basename(path)})",
)
except (json.JSONDecodeError, OSError):
continue
return _result("mcp_connection", "WARN", "MCP not configured — standalone mode active")

# ------------------------------------------------------------------
# Check 9: runtime mode
# ------------------------------------------------------------------
def check_runtime_mode(self) -> Dict[str, str]:
"""Detect current runtime mode (mcp or standalone)."""
mode = detect_runtime_mode(self._home_dir)
mode = detect_runtime_mode(self._home_dir, self._project_dir)
return _result("runtime_mode", "PASS", f"Runtime: {mode}")

# ------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion packages/claude-code-plugin/hooks/lib/history_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def close_instance(cls) -> None:
def __init__(self, db_path: str = None):
self._db_path = db_path or _default_db_path()
self._ensure_directory()
self._conn = sqlite3.connect(db_path, timeout=10)
self._conn = sqlite3.connect(self._db_path, timeout=10)
self._conn.execute("PRAGMA journal_mode=WAL")
self._set_file_permissions()
self._create_tables()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def build_system_prompt(self, config: Dict[str, Any], cwd: str) -> str:
if not isinstance(sections_cfg, dict):
sections_cfg = {}

mcp_mode = is_mcp_available()
mcp_mode = is_mcp_available(project_dir=cwd)

parts: list[str] = []

Expand Down
2 changes: 1 addition & 1 deletion packages/claude-code-plugin/hooks/user-prompt-submit.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def main():
from runtime_mode import is_mcp_available
from mode_engine import ModeEngine

if is_mcp_available():
if is_mcp_available(project_dir=os.getcwd()):
# MCP mode: minimal output, parse_mode handles the rest
print(f"# Mode: {detected_mode}")
print(
Expand Down
26 changes: 24 additions & 2 deletions packages/claude-code-plugin/tests/test_health_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,33 @@ def test_mcp_not_configured(self, env):
assert result["status"] == "WARN"
assert "standalone" in result["message"]

def test_mcp_json_missing(self, env):
def test_mcp_json_missing_falls_back_to_standalone(self, env):
checker = _make_checker(env)
result = checker.check_mcp_connection()
assert result["status"] == "WARN"
assert "not found" in result["message"]
assert "standalone" in result["message"]

def test_mcp_from_settings_json(self, env):
"""settings.json with codingbuddy mcpServers → PASS."""
settings_path = env / ".claude" / "settings.json"
settings = json.loads(settings_path.read_text())
settings["mcpServers"] = {"codingbuddy": {"command": "npx"}}
settings_path.write_text(json.dumps(settings))
checker = _make_checker(env)
result = checker.check_mcp_connection()
assert result["status"] == "PASS"
assert "settings.json" in result["message"]

def test_mcp_from_project_mcp_json(self, env):
"""project .mcp.json with codingbuddy → PASS."""
project_mcp = env / ".mcp.json"
project_mcp.write_text(json.dumps({
"mcpServers": {"codingbuddy": {"command": "npx"}}
}))
checker = _make_checker(env)
result = checker.check_mcp_connection()
assert result["status"] == "PASS"
assert ".mcp.json" in result["message"]


class TestCheckRuntimeMode:
Expand Down
18 changes: 18 additions & 0 deletions packages/claude-code-plugin/tests/test_history_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,24 @@ def writer2():
assert len(errors) == 0, f"Concurrent access errors: {errors}"


class TestDefaultConstructor:
"""HistoryDB() with no args should use default path and not raise."""

def test_default_constructor_does_not_raise(self, db_dir, monkeypatch):
"""HistoryDB() with no args must use self._db_path, not the original None."""
default_path = os.path.join(db_dir, "default", "history.db")
monkeypatch.setattr(
"hooks.lib.history_db._default_db_path", lambda: default_path
)
db = HistoryDB()
assert db._db_path == default_path
assert os.path.isfile(default_path)
db.start_session("default-test", project="/proj")
sessions = db.query_sessions(days=1)
assert len(sessions) == 1
db.close()


class TestSingleton:
"""Tests for HistoryDB singleton pattern (#931)."""

Expand Down
Loading