codegraph-cli 2.0.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 (43) hide show
  1. codegraph_cli/__init__.py +4 -0
  2. codegraph_cli/agents.py +191 -0
  3. codegraph_cli/bug_detector.py +386 -0
  4. codegraph_cli/chat_agent.py +352 -0
  5. codegraph_cli/chat_session.py +220 -0
  6. codegraph_cli/cli.py +330 -0
  7. codegraph_cli/cli_chat.py +367 -0
  8. codegraph_cli/cli_diagnose.py +133 -0
  9. codegraph_cli/cli_refactor.py +230 -0
  10. codegraph_cli/cli_setup.py +470 -0
  11. codegraph_cli/cli_test.py +177 -0
  12. codegraph_cli/cli_v2.py +267 -0
  13. codegraph_cli/codegen_agent.py +265 -0
  14. codegraph_cli/config.py +31 -0
  15. codegraph_cli/config_manager.py +341 -0
  16. codegraph_cli/context_manager.py +500 -0
  17. codegraph_cli/crew_agents.py +123 -0
  18. codegraph_cli/crew_chat.py +159 -0
  19. codegraph_cli/crew_tools.py +497 -0
  20. codegraph_cli/diff_engine.py +265 -0
  21. codegraph_cli/embeddings.py +241 -0
  22. codegraph_cli/graph_export.py +144 -0
  23. codegraph_cli/llm.py +642 -0
  24. codegraph_cli/models.py +47 -0
  25. codegraph_cli/models_v2.py +185 -0
  26. codegraph_cli/orchestrator.py +49 -0
  27. codegraph_cli/parser.py +800 -0
  28. codegraph_cli/performance_analyzer.py +223 -0
  29. codegraph_cli/project_context.py +230 -0
  30. codegraph_cli/rag.py +200 -0
  31. codegraph_cli/refactor_agent.py +452 -0
  32. codegraph_cli/security_scanner.py +366 -0
  33. codegraph_cli/storage.py +390 -0
  34. codegraph_cli/templates/graph_interactive.html +257 -0
  35. codegraph_cli/testgen_agent.py +316 -0
  36. codegraph_cli/validation_engine.py +285 -0
  37. codegraph_cli/vector_store.py +293 -0
  38. codegraph_cli-2.0.0.dist-info/METADATA +318 -0
  39. codegraph_cli-2.0.0.dist-info/RECORD +43 -0
  40. codegraph_cli-2.0.0.dist-info/WHEEL +5 -0
  41. codegraph_cli-2.0.0.dist-info/entry_points.txt +2 -0
  42. codegraph_cli-2.0.0.dist-info/licenses/LICENSE +21 -0
  43. codegraph_cli-2.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,185 @@
1
+ """Data models for v2.0 code generation features."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Any, Dict, List, Literal, Optional
7
+
8
+
9
+ @dataclass
10
+ class Location:
11
+ """Represents a location in source code."""
12
+ file_path: str
13
+ line: int
14
+ column: int = 0
15
+
16
+ def __str__(self) -> str:
17
+ return f"{self.file_path}:{self.line}"
18
+
19
+
20
+ @dataclass
21
+ class Range:
22
+ """Represents a range in source code."""
23
+ start: Location
24
+ end: Location
25
+
26
+ def __str__(self) -> str:
27
+ if self.start.file_path == self.end.file_path:
28
+ return f"{self.start.file_path}:{self.start.line}-{self.end.line}"
29
+ return f"{self.start} to {self.end}"
30
+
31
+
32
+ @dataclass
33
+ class FileChange:
34
+ """Represents changes to a single file."""
35
+ file_path: str
36
+ change_type: Literal["create", "modify", "delete"]
37
+ original_content: Optional[str] = None
38
+ new_content: Optional[str] = None
39
+ diff: str = ""
40
+
41
+ def __post_init__(self):
42
+ """Validate change type constraints."""
43
+ if self.change_type == "create" and self.original_content is not None:
44
+ raise ValueError("Create changes should not have original_content")
45
+ if self.change_type == "delete" and self.new_content is not None:
46
+ raise ValueError("Delete changes should not have new_content")
47
+ if self.change_type == "modify" and (self.original_content is None or self.new_content is None):
48
+ raise ValueError("Modify changes must have both original and new content")
49
+
50
+
51
+ @dataclass
52
+ class CodeProposal:
53
+ """Represents proposed code changes."""
54
+ id: str
55
+ description: str
56
+ changes: List[FileChange]
57
+ impact_summary: str = ""
58
+ metadata: Dict[str, Any] = field(default_factory=dict)
59
+
60
+ @property
61
+ def num_files_changed(self) -> int:
62
+ """Number of files affected."""
63
+ return len(self.changes)
64
+
65
+ @property
66
+ def num_files_created(self) -> int:
67
+ """Number of new files."""
68
+ return sum(1 for c in self.changes if c.change_type == "create")
69
+
70
+ @property
71
+ def num_files_modified(self) -> int:
72
+ """Number of modified files."""
73
+ return sum(1 for c in self.changes if c.change_type == "modify")
74
+
75
+ @property
76
+ def num_files_deleted(self) -> int:
77
+ """Number of deleted files."""
78
+ return sum(1 for c in self.changes if c.change_type == "delete")
79
+
80
+
81
+ @dataclass
82
+ class RefactorPlan:
83
+ """Represents a refactoring operation."""
84
+ refactor_type: str # "extract-function", "rename", "extract-service"
85
+ description: str
86
+ source_locations: List[Location]
87
+ target_location: Location
88
+ call_sites: List[Location]
89
+ changes: List[FileChange]
90
+
91
+ @property
92
+ def num_call_sites(self) -> int:
93
+ """Number of call sites that will be updated."""
94
+ return len(self.call_sites)
95
+
96
+
97
+ @dataclass
98
+ class TestCase:
99
+ """Represents a generated test."""
100
+ name: str
101
+ target_function: str
102
+ test_code: str
103
+ description: str
104
+ test_type: Literal["unit", "integration"] = "unit"
105
+ coverage_impact: float = 0.0
106
+
107
+ def __str__(self) -> str:
108
+ return f"Test: {self.name} for {self.target_function}"
109
+
110
+
111
+ @dataclass
112
+ class ApplyResult:
113
+ """Result of applying changes."""
114
+ success: bool
115
+ files_changed: List[str]
116
+ backup_id: Optional[str] = None
117
+ error: Optional[str] = None
118
+
119
+ def __str__(self) -> str:
120
+ if self.success:
121
+ return f"✅ Applied changes to {len(self.files_changed)} files"
122
+ return f"❌ Failed: {self.error}"
123
+
124
+
125
+ @dataclass
126
+ class ValidationResult:
127
+ """Result of validating code changes."""
128
+ valid: bool
129
+ errors: List[str] = field(default_factory=list)
130
+ warnings: List[str] = field(default_factory=list)
131
+
132
+ def __str__(self) -> str:
133
+ if self.valid:
134
+ return "✅ Validation passed"
135
+ return f"❌ Validation failed: {', '.join(self.errors)}"
136
+
137
+
138
+ @dataclass
139
+ class ChatMessage:
140
+ """Represents a single message in a chat conversation."""
141
+ role: Literal["user", "assistant", "system"]
142
+ content: str
143
+ timestamp: str
144
+ metadata: Dict[str, Any] = field(default_factory=dict)
145
+
146
+ def __str__(self) -> str:
147
+ return f"[{self.role}] {self.content[:100]}"
148
+
149
+
150
+ @dataclass
151
+ class ChatSession:
152
+ """Represents a chat session with conversation history."""
153
+ id: str
154
+ project_name: str
155
+ messages: List[ChatMessage] = field(default_factory=list)
156
+ pending_proposals: List[CodeProposal] = field(default_factory=list)
157
+ created_at: str = ""
158
+ updated_at: str = ""
159
+
160
+ def add_message(self, role: str, content: str, timestamp: str, metadata: Optional[Dict] = None):
161
+ """Add a message to the conversation."""
162
+ self.messages.append(ChatMessage(
163
+ role=role,
164
+ content=content,
165
+ timestamp=timestamp,
166
+ metadata=metadata or {}
167
+ ))
168
+ self.updated_at = timestamp
169
+
170
+ def clear_history(self):
171
+ """Clear all messages from this session."""
172
+ self.messages.clear()
173
+
174
+ def clear_proposals(self):
175
+ """Clear all pending proposals."""
176
+ self.pending_proposals.clear()
177
+
178
+ @property
179
+ def message_count(self) -> int:
180
+ """Number of messages in conversation."""
181
+ return len(self.messages)
182
+
183
+ def get_recent_messages(self, n: int = 3) -> List[ChatMessage]:
184
+ """Get the N most recent messages."""
185
+ return self.messages[-n:] if len(self.messages) >= n else self.messages
@@ -0,0 +1,49 @@
1
+ """MCP-style orchestrator coordinating specialized agents."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import Dict, List
7
+
8
+ from .agents import GraphAgent, RAGAgent, SummarizationAgent
9
+ from .embeddings import HashEmbeddingModel
10
+ from .llm import LocalLLM
11
+ from .models import ImpactReport, SearchResult
12
+ from .rag import RAGRetriever
13
+ from .storage import GraphStore
14
+
15
+
16
+ class MCPOrchestrator:
17
+ """Coordinates graph, retrieval, and summarization agents."""
18
+
19
+ def __init__(
20
+ self,
21
+ store: GraphStore,
22
+ llm_model: str = "qwen2.5-coder:7b",
23
+ llm_provider: str = "ollama",
24
+ llm_api_key: str | None = None,
25
+ llm_endpoint: str | None = None,
26
+ ):
27
+ self.store = store
28
+ self.embedding_model = HashEmbeddingModel()
29
+ self.graph_agent = GraphAgent(store, self.embedding_model)
30
+ self.rag_agent = RAGAgent(RAGRetriever(store, self.embedding_model))
31
+ self.summarization_agent = SummarizationAgent(
32
+ store,
33
+ LocalLLM(model=llm_model, provider=llm_provider, api_key=llm_api_key, endpoint=llm_endpoint),
34
+ )
35
+
36
+ def index(self, project_root: Path) -> Dict[str, int]:
37
+ return self.graph_agent.index_project(project_root)
38
+
39
+ def search(self, query: str, top_k: int = 5) -> List[SearchResult]:
40
+ return self.rag_agent.semantic_search(query, top_k=top_k)
41
+
42
+ def impact(self, symbol: str, hops: int = 2) -> ImpactReport:
43
+ return self.summarization_agent.impact_analysis(symbol=symbol, hops=hops)
44
+
45
+ def graph(self, symbol: str, depth: int = 2) -> str:
46
+ return self.graph_agent.ascii_neighbors(symbol=symbol, depth=depth)
47
+
48
+ def rag_context(self, query: str, top_k: int = 6) -> str:
49
+ return self.rag_agent.context_for_query(query, top_k=top_k)