Coverage for mcp_bridge/tools/project_context.py: 0%

1"""

2 Project Context and System Health Tools.

3

4 Provides the agent with environmental awareness (Git, Rules, Todos)

5 and ensures all required dependencies are installed and authenticated.

6"""

7

8 import os

9 import shutil

10 import subprocess

11 import sys

12 from pathlib import Path

13

14 from ..auth.token_store import TokenStore

15

16

17 async def get_project_context(project_path: str | None = None) -> str:

18 """

19 Summarize project environment: Git status, local rules, and pending todos.

20

21 Args:

22 project_path: Path to the project root

23

24 Returns:

25 Formatted summary of the project context.

26 """

27 root = Path(project_path) if project_path else Path.cwd()

28 context = []

29

30 # 1. Git Information

31 context.append("### 🌿 Git Context")

32 try:

33 branch = subprocess.check_output(

34 ["git", "rev-parse", "--abbrev-ref", "HEAD"],

35 stderr=subprocess.DEVNULL, text=True

36 ).strip()

37 status = subprocess.check_output(

38 ["git", "status", "--short"],

39 stderr=subprocess.DEVNULL, text=True

40 ).strip()

41

42 context.append(f"**Branch**: `{branch}`")

43 if status:

44 files_changed = len(status.split("\n"))

45 context.append(f"**Status**: {files_changed} files modified (staged/unstaged)")

46 else:

47 context.append("**Status**: Clean")

48 except Exception:

49 context.append("**Status**: Not a git repository")

50

51 # 2. Local Rules (.claude/rules/)

52 rules_dir = root / ".claude" / "rules"

53 if rules_dir.exists():

54 context.append("\n### 📜 Local Project Rules")

55 rule_files = list(rules_dir.glob("*.md"))

56 if rule_files:

57 for rf in rule_files:

58 try:

59 content = rf.read_text().strip()

60 context.append(f"#### {rf.name}\n{content}")

61 except Exception:

62 continue

63 else:

64 context.append("_No specific rules found in .claude/rules/_")

65

66 # 3. Pending Todos

67 context.append("\n### 📝 Pending Todos (Top 20)")

68 try:

69 # Search for [ ] in code files, excluding common noise directories

70 todo_cmd = [

71 "rg", "--line-number", "--no-heading", "--column",

72 "--glob", "!.git/*", "--glob", "!node_modules/*",

73 "--glob", "!.venv/*",

74 r"\[ \]", str(root)

75 ]

76 todo_output = subprocess.check_output(

77 todo_cmd, stderr=subprocess.DEVNULL, text=True

78 ).strip()

79

80 if todo_output:

81 lines = todo_output.split("\n")[:20]

82 for line in lines:

83 context.append(f"- {line}")

84 if len(todo_output.split("\n")) > 20:

85 context.append("_(... and more)_")

86 else:

87 context.append("_No pending [ ] markers found._")

88 except Exception:

89 context.append("_Ripgrep not found or error searching for todos._")

90

91 return "\n".join(context)

92

93

94 async def get_system_health() -> str:

95 """

96 Comprehensive check of system dependencies and authentication status.

97

98 Returns:

99 Checklist of system health.

100 """

101 health = ["## 🏥 Stravinsky System Health Report\n"]

102

103 # 1. CLI Dependencies

104 health.append("### 🛠️ CLI Dependencies")

105 dependencies = {

106 "rg": "ripgrep",

107 "fd": "fd-find",

108 "sg": "ast-grep",

109 "gh": "GitHub CLI",

110 "ruff": "Python Linter",

111 "tsc": "TypeScript Compiler",

112 "git": "Git"

113 }

114

115 for cmd, name in dependencies.items():

116 path = shutil.which(cmd)

117 status = "✅" if path else "❌"

118 health.append(f"- {status} **{name}** (`{cmd}`): {'Installed' if path else 'MISSING'}")

119

120 # 2. Authentication Status

121 health.append("\n### 🔑 Provider Authentication")

122 token_store = TokenStore()

123 providers = ["gemini", "openai"]

124

125 for p in providers:

126 has_token = token_store.has_valid_token(p)

127 status = "✅" if has_token else "❌"

128 health.append(f"- {status} **{p.capitalize()}**: {'Authenticated' if has_token else 'NOT LOGGED IN'}")

129

130 # 3. Environment

131 health.append("\n### 🐍 Environment")

132 health.append(f"- **Python**: `{sys.version.split()[0]}`")

133 health.append(f"- **Virtualenv**: `{os.environ.get('VIRTUAL_ENV', 'None')}`")

134

135 health.append("\n---")

136 health.append("**Resolution Guide**:")

137 health.append("- For missing CLI tools: Use `brew install` or `npm install -g` as appropriate.")

138 health.append("- For Auth: Run `python -m mcp_bridge.auth.cli login [provider]`.")

139

140 return "\n".join(health)