codecortex-context-engine 0.1.0a1__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 (90) hide show
  1. codecortex/__init__.py +3 -0
  2. codecortex/architecture/__init__.py +23 -0
  3. codecortex/architecture/drift.py +182 -0
  4. codecortex/architecture/inference.py +160 -0
  5. codecortex/backends/__init__.py +35 -0
  6. codecortex/backends/base.py +38 -0
  7. codecortex/backends/context.py +118 -0
  8. codecortex/backends/contracts.py +65 -0
  9. codecortex/backends/factory.py +60 -0
  10. codecortex/backends/graph.py +107 -0
  11. codecortex/backends/manager.py +303 -0
  12. codecortex/backends/mcp_client.py +196 -0
  13. codecortex/backends/pool.py +128 -0
  14. codecortex/backends/spec.py +83 -0
  15. codecortex/backends/symbols.py +189 -0
  16. codecortex/benchmark.py +211 -0
  17. codecortex/cli.py +409 -0
  18. codecortex/config.py +27 -0
  19. codecortex/context/__init__.py +13 -0
  20. codecortex/context/budget.py +62 -0
  21. codecortex/context/integrated.py +60 -0
  22. codecortex/context/pipeline.py +223 -0
  23. codecortex/core/__init__.py +1 -0
  24. codecortex/core/contracts.py +45 -0
  25. codecortex/core/errors.py +17 -0
  26. codecortex/core/models.py +69 -0
  27. codecortex/dashboard.py +259 -0
  28. codecortex/editing.py +41 -0
  29. codecortex/engines/__init__.py +5 -0
  30. codecortex/engines/builtin/__init__.py +5 -0
  31. codecortex/engines/builtin/factory.py +26 -0
  32. codecortex/engines/builtin/memory.py +35 -0
  33. codecortex/engines/builtin/repository.py +73 -0
  34. codecortex/engines/builtin/symbols.py +89 -0
  35. codecortex/engines/builtin/validation.py +54 -0
  36. codecortex/engines/registry.py +26 -0
  37. codecortex/entrypoint.py +266 -0
  38. codecortex/evaluation/__init__.py +55 -0
  39. codecortex/evaluation/external.py +265 -0
  40. codecortex/evaluation/production.py +670 -0
  41. codecortex/evaluation/regression.py +188 -0
  42. codecortex/gateway.py +38 -0
  43. codecortex/git_intelligence.py +252 -0
  44. codecortex/indexing/__init__.py +6 -0
  45. codecortex/indexing/graph.py +78 -0
  46. codecortex/indexing/impact.py +127 -0
  47. codecortex/indexing/incremental.py +163 -0
  48. codecortex/indexing/incremental_graph.py +189 -0
  49. codecortex/indexing/indexer.py +172 -0
  50. codecortex/indexing/relationships.py +179 -0
  51. codecortex/indexing/resolution.py +88 -0
  52. codecortex/integrations/__init__.py +5 -0
  53. codecortex/integrations/agents.py +235 -0
  54. codecortex/interfaces/__init__.py +1 -0
  55. codecortex/interfaces/mcp_bridge.py +66 -0
  56. codecortex/languages/__init__.py +5 -0
  57. codecortex/languages/native.py +166 -0
  58. codecortex/languages/registry.py +232 -0
  59. codecortex/mcp/__init__.py +5 -0
  60. codecortex/mcp/extended.py +114 -0
  61. codecortex/mcp/server.py +473 -0
  62. codecortex/memory/__init__.py +11 -0
  63. codecortex/memory/json_store.py +52 -0
  64. codecortex/memory/knowledge.py +193 -0
  65. codecortex/memory/team_store.py +193 -0
  66. codecortex/orchestrator.py +153 -0
  67. codecortex/pr_intelligence.py +214 -0
  68. codecortex/retrieval/__init__.py +16 -0
  69. codecortex/retrieval/hybrid.py +67 -0
  70. codecortex/retrieval/index.py +135 -0
  71. codecortex/retrieval/providers.py +67 -0
  72. codecortex/retrieval/repository.py +94 -0
  73. codecortex/router/__init__.py +5 -0
  74. codecortex/router/router.py +79 -0
  75. codecortex/runtime.py +69 -0
  76. codecortex/setup.py +100 -0
  77. codecortex/symbols/__init__.py +5 -0
  78. codecortex/symbols/providers.py +192 -0
  79. codecortex/telemetry/__init__.py +5 -0
  80. codecortex/telemetry/collector.py +43 -0
  81. codecortex/tracing/__init__.py +9 -0
  82. codecortex/tracing/task_trace.py +235 -0
  83. codecortex/workspace/__init__.py +9 -0
  84. codecortex/workspace/federation.py +173 -0
  85. codecortex_context_engine-0.1.0a1.dist-info/METADATA +381 -0
  86. codecortex_context_engine-0.1.0a1.dist-info/RECORD +90 -0
  87. codecortex_context_engine-0.1.0a1.dist-info/WHEEL +4 -0
  88. codecortex_context_engine-0.1.0a1.dist-info/entry_points.txt +3 -0
  89. codecortex_context_engine-0.1.0a1.dist-info/licenses/LICENSE +201 -0
  90. codecortex_context_engine-0.1.0a1.dist-info/licenses/NOTICE +2 -0
@@ -0,0 +1,232 @@
1
+ """Language-aware parsing, type discovery, and structural extraction."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import ast
6
+ import re
7
+ from dataclasses import dataclass, field
8
+ from pathlib import Path
9
+
10
+ from codecortex.languages.native import TreeSitterParserProvider
11
+
12
+
13
+ @dataclass(frozen=True, slots=True)
14
+ class ParsedUnit:
15
+ name: str
16
+ kind: str
17
+ line: int
18
+ end_line: int | None = None
19
+ signature: str | None = None
20
+ return_type: str | None = None
21
+ type_parameters: tuple[str, ...] = ()
22
+ bases: tuple[str, ...] = ()
23
+ modifiers: tuple[str, ...] = ()
24
+ references: tuple[str, ...] = ()
25
+ annotations: dict[str, str] = field(default_factory=dict)
26
+
27
+
28
+ @dataclass(frozen=True, slots=True)
29
+ class LanguageSpec:
30
+ name: str
31
+ suffixes: tuple[str, ...]
32
+ parser: str
33
+
34
+
35
+ class LanguageRegistry:
36
+ """Use precise Python AST, optional Tree-sitter grammars, then conservative fallback."""
37
+
38
+ _SPECS = (
39
+ LanguageSpec("python", (".py",), "python_ast"),
40
+ LanguageSpec("typescript", (".ts", ".tsx"), "native"),
41
+ LanguageSpec("javascript", (".js", ".jsx", ".mjs", ".cjs"), "native"),
42
+ LanguageSpec("go", (".go",), "native"),
43
+ LanguageSpec("rust", (".rs",), "native"),
44
+ LanguageSpec("java", (".java",), "native"),
45
+ LanguageSpec("c", (".c", ".h"), "native"),
46
+ LanguageSpec("cpp", (".cc", ".cpp", ".cxx", ".hpp", ".hh"), "native"),
47
+ LanguageSpec("csharp", (".cs",), "native"),
48
+ LanguageSpec("php", (".php",), "native"),
49
+ LanguageSpec("ruby", (".rb",), "native"),
50
+ )
51
+
52
+ def __init__(self, *, native: bool = True) -> None:
53
+ self.native = (
54
+ TreeSitterParserProvider()
55
+ if native and TreeSitterParserProvider.available()
56
+ else None
57
+ )
58
+
59
+ def language_for(self, path: Path) -> LanguageSpec | None:
60
+ suffix = path.suffix.lower()
61
+ return next((spec for spec in self._SPECS if suffix in spec.suffixes), None)
62
+
63
+ def parse(self, path: Path, source: str) -> list[ParsedUnit]:
64
+ spec = self.language_for(path)
65
+ if spec is None:
66
+ return []
67
+ if spec.parser == "python_ast":
68
+ return self._parse_python(source)
69
+ if self.native is not None:
70
+ try:
71
+ units = self.native.parse(spec.name, source)
72
+ except Exception:
73
+ units = []
74
+ if units:
75
+ return [
76
+ ParsedUnit(
77
+ name=item.name,
78
+ kind=item.kind,
79
+ line=item.line,
80
+ end_line=item.end_line,
81
+ signature=item.signature,
82
+ return_type=item.return_type,
83
+ bases=item.bases,
84
+ references=item.references,
85
+ )
86
+ for item in units
87
+ ]
88
+ return self._parse_structural(spec.name, source)
89
+
90
+ def _parse_python(self, source: str) -> list[ParsedUnit]:
91
+ try:
92
+ tree = ast.parse(source)
93
+ except SyntaxError:
94
+ return []
95
+ units: list[ParsedUnit] = []
96
+ for node in ast.walk(tree):
97
+ if isinstance(node, ast.ClassDef):
98
+ units.append(
99
+ ParsedUnit(
100
+ name=node.name,
101
+ kind="class",
102
+ line=node.lineno,
103
+ end_line=getattr(node, "end_lineno", None),
104
+ bases=tuple(ast.unparse(base) for base in node.bases),
105
+ type_parameters=tuple(
106
+ getattr(item, "name", ast.unparse(item))
107
+ for item in getattr(node, "type_params", [])
108
+ ),
109
+ )
110
+ )
111
+ elif isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
112
+ args = [arg.arg for arg in node.args.posonlyargs + node.args.args]
113
+ args.extend(f"*{arg.arg}" for arg in node.args.kwonlyargs)
114
+ if node.args.vararg:
115
+ args.append(f"*{node.args.vararg.arg}")
116
+ if node.args.kwarg:
117
+ args.append(f"**{node.args.kwarg.arg}")
118
+ refs = tuple(
119
+ child.id
120
+ for child in ast.walk(node)
121
+ if isinstance(child, ast.Name) and isinstance(child.ctx, ast.Load)
122
+ )
123
+ units.append(
124
+ ParsedUnit(
125
+ name=node.name,
126
+ kind=(
127
+ "async_function"
128
+ if isinstance(node, ast.AsyncFunctionDef)
129
+ else "function"
130
+ ),
131
+ line=node.lineno,
132
+ end_line=getattr(node, "end_lineno", None),
133
+ signature=f"({', '.join(args)})",
134
+ return_type=ast.unparse(node.returns) if node.returns else None,
135
+ references=refs,
136
+ annotations={
137
+ arg.arg: ast.unparse(arg.annotation)
138
+ for arg in node.args.args
139
+ if arg.annotation is not None
140
+ },
141
+ )
142
+ )
143
+ return units
144
+
145
+ def _parse_structural(self, language: str, source: str) -> list[ParsedUnit]:
146
+ units: list[ParsedUnit] = []
147
+ patterns = self._patterns(language)
148
+ for line_no, line in enumerate(source.splitlines(), 1):
149
+ stripped = line.strip()
150
+ for kind, pattern in patterns:
151
+ match = pattern.search(stripped)
152
+ if not match:
153
+ continue
154
+ name = match.group("name")
155
+ bases = tuple(
156
+ item.strip()
157
+ for item in (match.groupdict().get("bases") or "").split(",")
158
+ if item.strip()
159
+ )
160
+ units.append(
161
+ ParsedUnit(
162
+ name=name,
163
+ kind=kind,
164
+ line=line_no,
165
+ signature=match.groupdict().get("signature"),
166
+ return_type=match.groupdict().get("return"),
167
+ bases=bases,
168
+ modifiers=tuple(
169
+ item
170
+ for item in (match.groupdict().get("mods") or "").split()
171
+ if item
172
+ ),
173
+ )
174
+ )
175
+ break
176
+ return units
177
+
178
+ @staticmethod
179
+ def _patterns(language: str) -> tuple[tuple[str, re.Pattern[str]], ...]:
180
+ common_class = re.compile(
181
+ r"(?P<mods>(?:(?:export|public|private|protected|abstract|final|sealed|static)\s+)*)"
182
+ r"(?:class|interface|trait|struct|enum)\s+(?P<name>[A-Za-z_][\w$]*)"
183
+ r"(?:\s+(?:extends|implements|:)\s+(?P<bases>[^\{]+))?"
184
+ )
185
+ c_like_function = re.compile(
186
+ r"(?P<mods>(?:(?:export|public|private|protected|static|async|virtual|override|final|unsafe)\s+)*)"
187
+ r"(?:(?P<return>[A-Za-z_][\w:<>,\[\]?*& ]*)\s+)?"
188
+ r"(?P<name>[A-Za-z_][\w$]*)\s*(?P<signature>\([^;{}]*\))\s*(?:\{|=>)"
189
+ )
190
+ function_keyword = re.compile(
191
+ r"(?P<mods>(?:(?:export|async|pub|unsafe)\s+)*)"
192
+ r"(?:function|fn|func|def)\s+(?P<name>[A-Za-z_][\w$!?]*)\s*(?P<signature>\([^)]*\))"
193
+ r"(?:\s*(?:->|:)\s*(?P<return>[^\{=]+))?"
194
+ )
195
+ arrow = re.compile(
196
+ r"(?:(?:export|const|let|var)\s+)+(?P<name>[A-Za-z_$][\w$]*)\s*=\s*"
197
+ r"(?:async\s+)?(?P<signature>\([^)]*\)|[A-Za-z_$][\w$]*)\s*=>"
198
+ )
199
+ ruby_class = re.compile(r"(?:class|module)\s+(?P<name>[A-Za-z_][\w:]*)")
200
+ if language == "ruby":
201
+ return (("class", ruby_class), ("function", function_keyword))
202
+ if language in {"typescript", "javascript"}:
203
+ return (
204
+ ("class", common_class),
205
+ ("function", function_keyword),
206
+ ("function", arrow),
207
+ ("function", c_like_function),
208
+ )
209
+ return (
210
+ ("class", common_class),
211
+ ("function", function_keyword),
212
+ ("function", c_like_function),
213
+ )
214
+
215
+ def resolve_types(self, units: list[ParsedUnit]) -> dict[str, set[str]]:
216
+ names = {unit.name for unit in units}
217
+ resolved: dict[str, set[str]] = {}
218
+ for unit in units:
219
+ candidates = set(unit.bases)
220
+ candidates.update(unit.annotations.values())
221
+ if unit.return_type:
222
+ candidates.add(unit.return_type)
223
+ matches = {
224
+ name
225
+ for name in names
226
+ if any(
227
+ re.search(rf"\b{re.escape(name)}\b", candidate)
228
+ for candidate in candidates
229
+ )
230
+ }
231
+ resolved[unit.name] = matches
232
+ return resolved
@@ -0,0 +1,5 @@
1
+ """Native MCP server."""
2
+
3
+ from codecortex.mcp.server import MCPApplication, MCPServer
4
+
5
+ __all__ = ["MCPApplication", "MCPServer"]
@@ -0,0 +1,114 @@
1
+ """Extended MCP application exposing guarded semantic editing tools."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from codecortex.editing import EditService
10
+ from codecortex.mcp.server import MCPApplication, MCPServer
11
+ from codecortex.runtime import build_runtime
12
+
13
+
14
+ def _schema(properties: dict[str, Any], required: list[str]) -> dict[str, Any]:
15
+ return {
16
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
17
+ "type": "object",
18
+ "properties": properties,
19
+ "required": required,
20
+ "additionalProperties": False,
21
+ }
22
+
23
+
24
+ _EDIT_TOOLS = {
25
+ "cortex_rename_symbol",
26
+ "cortex_replace_symbol_body",
27
+ "cortex_insert_before_symbol",
28
+ "cortex_insert_after_symbol",
29
+ }
30
+
31
+
32
+ class ExtendedMCPApplication(MCPApplication):
33
+ def tools(self) -> list[dict[str, Any]]:
34
+ tools = super().tools()
35
+ text = {"type": "string", "minLength": 1}
36
+ tools.extend(
37
+ [
38
+ {
39
+ "name": "cortex_rename_symbol",
40
+ "description": "Rename a symbol across the codebase using language-server refactoring.",
41
+ "inputSchema": _schema(
42
+ {"path": text, "name_path": text, "new_name": text},
43
+ ["path", "name_path", "new_name"],
44
+ ),
45
+ },
46
+ {
47
+ "name": "cortex_replace_symbol_body",
48
+ "description": "Replace one symbol definition after a semantic preflight read.",
49
+ "inputSchema": _schema(
50
+ {"path": text, "name_path": text, "body": text},
51
+ ["path", "name_path", "body"],
52
+ ),
53
+ },
54
+ {
55
+ "name": "cortex_insert_before_symbol",
56
+ "description": "Insert code immediately before a semantic symbol.",
57
+ "inputSchema": _schema(
58
+ {"path": text, "name_path": text, "body": text},
59
+ ["path", "name_path", "body"],
60
+ ),
61
+ },
62
+ {
63
+ "name": "cortex_insert_after_symbol",
64
+ "description": "Insert code immediately after a semantic symbol.",
65
+ "inputSchema": _schema(
66
+ {"path": text, "name_path": text, "body": text},
67
+ ["path", "name_path", "body"],
68
+ ),
69
+ },
70
+ ]
71
+ )
72
+ return tools
73
+
74
+ async def call(self, name: str, arguments: dict[str, Any]) -> dict[str, Any]:
75
+ self.runtime.telemetry.emit("mcp.tool.called", tool=name)
76
+ if name not in _EDIT_TOOLS:
77
+ return await super().call(name, arguments)
78
+ service = EditService(self.runtime)
79
+ path = str(arguments["path"])
80
+ name_path = str(arguments["name_path"])
81
+ if name == "cortex_rename_symbol":
82
+ payload = await asyncio.to_thread(
83
+ service.rename,
84
+ path,
85
+ name_path,
86
+ str(arguments["new_name"]),
87
+ )
88
+ elif name == "cortex_replace_symbol_body":
89
+ payload = await asyncio.to_thread(
90
+ service.replace,
91
+ path,
92
+ name_path,
93
+ str(arguments["body"]),
94
+ )
95
+ elif name == "cortex_insert_before_symbol":
96
+ payload = await asyncio.to_thread(
97
+ service.insert_before,
98
+ path,
99
+ name_path,
100
+ str(arguments["body"]),
101
+ )
102
+ else:
103
+ payload = await asyncio.to_thread(
104
+ service.insert_after,
105
+ path,
106
+ name_path,
107
+ str(arguments["body"]),
108
+ )
109
+ return {"edited": True, "operation": name, "backend_result": payload}
110
+
111
+
112
+ def run_stdio(project_root: Path | None = None) -> None:
113
+ runtime = build_runtime(project_root)
114
+ asyncio.run(MCPServer(ExtendedMCPApplication(runtime)).serve_stdio())