codevira 1.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. codevira-1.6.0.dist-info/LICENSE +21 -0
  2. codevira-1.6.0.dist-info/METADATA +477 -0
  3. codevira-1.6.0.dist-info/RECORD +58 -0
  4. codevira-1.6.0.dist-info/WHEEL +5 -0
  5. codevira-1.6.0.dist-info/entry_points.txt +2 -0
  6. codevira-1.6.0.dist-info/top_level.txt +2 -0
  7. indexer/__init__.py +1 -0
  8. indexer/chunker.py +428 -0
  9. indexer/global_db.py +197 -0
  10. indexer/graph_generator.py +380 -0
  11. indexer/index_codebase.py +588 -0
  12. indexer/outcome_tracker.py +172 -0
  13. indexer/rule_learner.py +186 -0
  14. indexer/sqlite_graph.py +640 -0
  15. indexer/treesitter_parser.py +423 -0
  16. mcp_server/__init__.py +1 -0
  17. mcp_server/__main__.py +20 -0
  18. mcp_server/auto_init.py +257 -0
  19. mcp_server/cli.py +622 -0
  20. mcp_server/crash_logger.py +236 -0
  21. mcp_server/data/__init__.py +1 -0
  22. mcp_server/data/agents/builder.md +84 -0
  23. mcp_server/data/agents/developer.md +111 -0
  24. mcp_server/data/agents/documenter.md +138 -0
  25. mcp_server/data/agents/orchestrator.md +96 -0
  26. mcp_server/data/agents/planner.md +106 -0
  27. mcp_server/data/agents/reviewer.md +82 -0
  28. mcp_server/data/agents/tester.md +83 -0
  29. mcp_server/data/config.example.yaml +33 -0
  30. mcp_server/data/rules/coding-standards.md +48 -0
  31. mcp_server/data/rules/engineering-excellence.md +28 -0
  32. mcp_server/data/rules/git-cicd-governance.md +32 -0
  33. mcp_server/data/rules/git_commits.md +130 -0
  34. mcp_server/data/rules/incremental-updates.md +5 -0
  35. mcp_server/data/rules/master_rule.md +187 -0
  36. mcp_server/data/rules/multi-language.md +19 -0
  37. mcp_server/data/rules/persistence.md +21 -0
  38. mcp_server/data/rules/resilience-observability.md +17 -0
  39. mcp_server/data/rules/smoke-testing.md +48 -0
  40. mcp_server/data/rules/testing-standards.md +23 -0
  41. mcp_server/detect.py +284 -0
  42. mcp_server/gitignore.py +284 -0
  43. mcp_server/global_sync.py +187 -0
  44. mcp_server/http_server.py +341 -0
  45. mcp_server/ide_inject.py +444 -0
  46. mcp_server/launchd.py +156 -0
  47. mcp_server/migrate.py +215 -0
  48. mcp_server/paths.py +256 -0
  49. mcp_server/prompts.py +136 -0
  50. mcp_server/server.py +1049 -0
  51. mcp_server/tools/__init__.py +0 -0
  52. mcp_server/tools/changesets.py +223 -0
  53. mcp_server/tools/code_reader.py +335 -0
  54. mcp_server/tools/graph.py +637 -0
  55. mcp_server/tools/learning.py +238 -0
  56. mcp_server/tools/playbook.py +89 -0
  57. mcp_server/tools/roadmap.py +599 -0
  58. mcp_server/tools/search.py +145 -0
@@ -0,0 +1,238 @@
1
+ """
2
+ Learning tools — MCP tools for Codevira's adaptive memory system.
3
+
4
+ These tools expose the feedback loop to AI agents:
5
+ - get_decision_confidence: How confident is the system about decisions in an area?
6
+ - get_preferences: What coding style does the developer prefer?
7
+ - get_learned_rules: Auto-generated rules from observed patterns
8
+ - get_project_maturity: Overall project intelligence score
9
+ - get_session_context: Single "catch me up" call for cross-tool continuity
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import json
14
+ import logging
15
+ from mcp_server.paths import get_data_dir
16
+ from indexer.sqlite_graph import SQLiteGraph
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ def _get_db() -> SQLiteGraph:
22
+ return SQLiteGraph(get_data_dir() / "graph" / "graph.db")
23
+
24
+
25
+ def get_decision_confidence(file_path: str | None = None, pattern: str | None = None) -> dict:
26
+ """Get confidence scores for decisions about a file or pattern."""
27
+ db = _get_db()
28
+ try:
29
+ confidence = db.get_decision_confidence(file_path=file_path, pattern=pattern)
30
+ label = file_path or pattern or "project-wide"
31
+ return {
32
+ "scope": label,
33
+ **confidence,
34
+ "interpretation": _interpret_confidence(confidence["confidence"]),
35
+ }
36
+ finally:
37
+ db.close()
38
+
39
+
40
+ def get_preferences(category: str | None = None) -> dict:
41
+ """Get learned developer preferences."""
42
+ db = _get_db()
43
+ try:
44
+ prefs = db.get_preferences(category=category, min_frequency=1)
45
+ return {
46
+ "preferences": prefs,
47
+ "total": len(prefs),
48
+ "hint": "Apply these preferences when writing code to match the developer's style."
49
+ if prefs else "No preferences learned yet. They build up over sessions.",
50
+ }
51
+ finally:
52
+ db.close()
53
+
54
+
55
+ def get_learned_rules(file_path: str | None = None, category: str | None = None) -> dict:
56
+ """Get auto-generated rules from observed patterns."""
57
+ db = _get_db()
58
+ try:
59
+ rules = db.get_learned_rules(category=category, file_pattern=file_path, min_confidence=0.3)
60
+ return {
61
+ "rules": [
62
+ {
63
+ "rule": r["rule_text"],
64
+ "confidence": r["confidence"],
65
+ "category": r["category"],
66
+ "applies_to": r.get("file_pattern"),
67
+ }
68
+ for r in rules
69
+ ],
70
+ "total": len(rules),
71
+ "hint": "These rules were learned from past sessions. Higher confidence = more reliable."
72
+ if rules else "No rules learned yet. They emerge after multiple sessions.",
73
+ }
74
+ finally:
75
+ db.close()
76
+
77
+
78
+ def get_project_maturity() -> dict:
79
+ """Get overall project intelligence and maturity metrics."""
80
+ db = _get_db()
81
+ try:
82
+ maturity = db.get_project_maturity()
83
+ score = _compute_maturity_score(maturity)
84
+ return {
85
+ **maturity,
86
+ "maturity_score": score,
87
+ "maturity_level": _maturity_level(score),
88
+ "hint": _maturity_hint(score),
89
+ }
90
+ finally:
91
+ db.close()
92
+
93
+
94
+ def get_session_context() -> dict:
95
+ """
96
+ Single 'catch me up' call for cross-tool continuity.
97
+ Returns everything a new agent session needs to understand the current state:
98
+ current roadmap phase, open changesets, recent decisions with confidence, and recent sessions.
99
+ """
100
+ db = _get_db()
101
+ try:
102
+ # Recent sessions
103
+ recent_sessions = db.get_recent_sessions(limit=3)
104
+
105
+ # Recent decisions with confidence
106
+ recent_decisions = db.get_recent_decisions(limit=5)
107
+
108
+ # Confidence overview
109
+ confidence = db.get_decision_confidence()
110
+
111
+ # Preferences summary (top 5 by frequency)
112
+ prefs = db.get_preferences(min_frequency=2)[:5]
113
+
114
+ # Learned rules (high confidence only)
115
+ rules = db.get_learned_rules(min_confidence=0.6)[:5]
116
+
117
+ context = {
118
+ "recent_sessions": [
119
+ {
120
+ "session_id": s["session_id"],
121
+ "summary": s.get("summary"),
122
+ "phase": s.get("phase"),
123
+ }
124
+ for s in recent_sessions
125
+ ],
126
+ "recent_decisions": [
127
+ {
128
+ "decision": d["decision"],
129
+ "file_path": d.get("file_path"),
130
+ "phase": d.get("phase"),
131
+ }
132
+ for d in recent_decisions
133
+ ],
134
+ "overall_confidence": confidence,
135
+ "top_preferences": [
136
+ {"category": p["category"], "signal": p["signal"], "frequency": p["frequency"]}
137
+ for p in prefs
138
+ ],
139
+ "top_rules": [
140
+ {"rule": r["rule_text"], "confidence": r["confidence"]}
141
+ for r in rules
142
+ ],
143
+ }
144
+
145
+ # Add roadmap context if available
146
+ try:
147
+ from mcp_server.tools.roadmap import get_roadmap
148
+ roadmap = get_roadmap()
149
+ context["roadmap"] = {
150
+ "current_phase": roadmap.get("current_phase", {}).get("name"),
151
+ "next_action": roadmap.get("current_phase", {}).get("next_action"),
152
+ "status": roadmap.get("current_phase", {}).get("status"),
153
+ }
154
+ except Exception as e:
155
+ logger.warning("Could not load roadmap context: %s", e)
156
+ context["roadmap"] = None
157
+
158
+ # Add open changesets if any
159
+ try:
160
+ from mcp_server.tools.changesets import list_open_changesets
161
+ changesets = list_open_changesets()
162
+ context["open_changesets"] = changesets.get("changesets", [])
163
+ except Exception as e:
164
+ logger.warning("Could not load changesets context: %s", e)
165
+ context["open_changesets"] = []
166
+
167
+ # v1.5: Add global intelligence stats
168
+ try:
169
+ from mcp_server.global_sync import get_global_stats
170
+ context["global_intelligence"] = get_global_stats()
171
+ except Exception as e:
172
+ logger.warning("Could not load global intelligence: %s", e)
173
+ context["global_intelligence"] = None
174
+
175
+ # v1.6: Add indexing progress if background init is running
176
+ try:
177
+ from mcp_server.auto_init import get_init_progress
178
+ prog = get_init_progress()
179
+ if prog["status"] not in ("ready", "not_started"):
180
+ context["indexing_progress"] = prog
181
+ except Exception:
182
+ pass
183
+
184
+ return context
185
+ finally:
186
+ db.close()
187
+
188
+
189
+ def _interpret_confidence(score: float) -> str:
190
+ if score >= 0.8:
191
+ return "High confidence — consistent successful patterns in this area."
192
+ elif score >= 0.5:
193
+ return "Moderate confidence — some patterns established but results are mixed."
194
+ elif score > 0:
195
+ return "Low confidence — limited history or frequent corrections. Proceed carefully."
196
+ return "No data — this is new territory. Decisions here will build the baseline."
197
+
198
+
199
+ def _compute_maturity_score(maturity: dict) -> float:
200
+ """Compute a 0-100 maturity score from multiple signals."""
201
+ score = 0.0
202
+
203
+ # Sessions (max 20 points)
204
+ score += min(maturity["session_count"] * 2, 20)
205
+
206
+ # Coverage (max 30 points)
207
+ score += maturity["coverage"] * 30
208
+
209
+ # Confidence (max 25 points)
210
+ score += maturity["overall_confidence"] * 25
211
+
212
+ # Learned rules (max 15 points)
213
+ score += min(maturity["learned_rules"] * 3, 15)
214
+
215
+ # Preferences (max 10 points)
216
+ score += min(maturity["preference_signals"] * 2, 10)
217
+
218
+ return round(min(score, 100), 1)
219
+
220
+
221
+ def _maturity_level(score: float) -> str:
222
+ if score >= 80:
223
+ return "Expert — agents have rich context and high confidence."
224
+ elif score >= 50:
225
+ return "Intermediate — good coverage, patterns emerging."
226
+ elif score >= 20:
227
+ return "Growing — some sessions logged, building baseline."
228
+ return "New — fresh project, minimal agent memory."
229
+
230
+
231
+ def _maturity_hint(score: float) -> str:
232
+ if score >= 80:
233
+ return "Project memory is mature. Agents should rely on learned patterns and confidence scores."
234
+ elif score >= 50:
235
+ return "Good progress. Continue using Codevira — confidence and rules will keep improving."
236
+ elif score >= 20:
237
+ return "Still building memory. Run more agent sessions and outcomes will start influencing confidence."
238
+ return "This is a fresh start. Every session logs decisions that future agents will learn from."
@@ -0,0 +1,89 @@
1
+ """
2
+ MCP tool for retrieving curated rule playbooks by task type.
3
+ Serves the right 2-3 rule files for a given task — not all of them.
4
+ """
5
+ from __future__ import annotations
6
+
7
+ from pathlib import Path
8
+
9
+ from mcp_server.paths import get_package_data_dir
10
+
11
+
12
+ def _rules_dir() -> Path:
13
+ return get_package_data_dir() / "rules"
14
+
15
+ # Task type → relevant rule files (ordered by importance)
16
+ # These map common development tasks to the rule files that govern them.
17
+ PLAYBOOKS: dict[str, list[str]] = {
18
+ "add_tool": [
19
+ "coding-standards.md",
20
+ "testing-standards.md",
21
+ ],
22
+ "add_service": [
23
+ "coding-standards.md",
24
+ "resilience-observability.md",
25
+ ],
26
+ "add_schema": [
27
+ "coding-standards.md",
28
+ "persistence.md",
29
+ ],
30
+ "debug_pipeline": [
31
+ "resilience-observability.md",
32
+ "coding-standards.md",
33
+ ],
34
+ "commit": [
35
+ "git_commits.md",
36
+ "git-cicd-governance.md",
37
+ ],
38
+ "write_test": [
39
+ "testing-standards.md",
40
+ "smoke-testing.md",
41
+ ],
42
+ }
43
+
44
+
45
+ def get_playbook(task_type: str) -> dict:
46
+ """
47
+ Return curated rule content for a specific task type.
48
+ Serves only the relevant 2-3 rule files, not all of them.
49
+
50
+ Args:
51
+ task_type: One of add_route | add_service | add_schema |
52
+ debug_pipeline | commit | write_test
53
+
54
+ Returns:
55
+ Dict with task_type, rules (list of {file, content}), token_note.
56
+ """
57
+ task_type = task_type.lower().strip()
58
+
59
+ if task_type not in PLAYBOOKS:
60
+ return {
61
+ "found": False,
62
+ "task_type": task_type,
63
+ "available_task_types": sorted(PLAYBOOKS.keys()),
64
+ "hint": "Use get_node() for file-specific rules embedded in the context graph.",
65
+ }
66
+
67
+ rule_files = PLAYBOOKS[task_type]
68
+ rules = []
69
+
70
+ for filename in rule_files:
71
+ path = _rules_dir() / filename
72
+ if path.exists():
73
+ rules.append({
74
+ "file": filename,
75
+ "content": path.read_text().strip(),
76
+ })
77
+ else:
78
+ rules.append({
79
+ "file": filename,
80
+ "content": f"[File not found: {path}]",
81
+ })
82
+
83
+ return {
84
+ "found": True,
85
+ "task_type": task_type,
86
+ "rules": rules,
87
+ "note": f"Serving {len(rules)} rule files for '{task_type}'. "
88
+ f"File-specific rules are in get_node() → rules field.",
89
+ }