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,26 @@
1
+ """Default local engine assembly."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from codecortex.config import CortexConfig
6
+ from codecortex.core.contracts import MemoryStore
7
+ from codecortex.engines.builtin.memory import MemoryEngine
8
+ from codecortex.engines.builtin.repository import RepositoryEngine
9
+ from codecortex.engines.builtin.symbols import SymbolEngine
10
+ from codecortex.engines.builtin.validation import ValidationEngine
11
+ from codecortex.engines.registry import EngineRegistry
12
+ from codecortex.memory import JsonMemoryStore
13
+
14
+
15
+ def build_default_registry(
16
+ config: CortexConfig,
17
+ memory_store: MemoryStore | None = None,
18
+ ) -> EngineRegistry:
19
+ config.ensure_directories()
20
+ memory = memory_store or JsonMemoryStore(config.memory_dir)
21
+ registry = EngineRegistry()
22
+ registry.register(RepositoryEngine(config.project_root))
23
+ registry.register(SymbolEngine(config.project_root))
24
+ registry.register(MemoryEngine(memory))
25
+ registry.register(ValidationEngine(config.project_root))
26
+ return registry
@@ -0,0 +1,35 @@
1
+ """Memory search engine."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from codecortex.core.contracts import Engine, MemoryStore
6
+ from codecortex.core.models import AgentRequest, Capability, ContextChunk, EngineResult
7
+
8
+
9
+ class MemoryEngine(Engine):
10
+ capability = Capability.MEMORY
11
+
12
+ def __init__(self, store: MemoryStore, namespace: str = "project") -> None:
13
+ self.store = store
14
+ self.namespace = namespace
15
+
16
+ async def health(self) -> bool:
17
+ return True
18
+
19
+ async def execute(self, request: AgentRequest) -> EngineResult:
20
+ matches = await self.store.search(self.namespace, request.query, limit=10)
21
+ content = "\n\n".join(matches) if matches else "No matching project memory found."
22
+ return EngineResult(
23
+ capability=self.capability,
24
+ content=content,
25
+ chunks=[
26
+ ContextChunk(
27
+ source="project-memory",
28
+ content=content,
29
+ tokens=max(1, len(content) // 4),
30
+ relevance=0.75 if matches else 0.20,
31
+ metadata={"matches": len(matches)},
32
+ )
33
+ ],
34
+ metadata={"matches": len(matches)},
35
+ )
@@ -0,0 +1,73 @@
1
+ """Graph-backed local repository intelligence engine."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from codecortex.core.contracts import Engine
8
+ from codecortex.core.models import AgentRequest, Capability, ContextChunk, EngineResult
9
+ from codecortex.indexing import ProjectIndexer
10
+
11
+
12
+ class RepositoryEngine(Engine):
13
+ capability = Capability.REPOSITORY
14
+
15
+ def __init__(self, project_root: Path, max_files: int = 5_000) -> None:
16
+ self.project_root = project_root.resolve()
17
+ self.max_files = max_files
18
+
19
+ async def health(self) -> bool:
20
+ return self.project_root.exists() and self.project_root.is_dir()
21
+
22
+ async def execute(self, request: AgentRequest) -> EngineResult:
23
+ graph = ProjectIndexer(self.project_root, max_files=self.max_files).build()
24
+ graph_path = self.project_root / ".codecortex" / "index" / "graph.json"
25
+ graph.save(graph_path)
26
+
27
+ counts = graph.counts()
28
+ matches = graph.search(request.query)
29
+ import_edges = sum(1 for edge in graph.edges if edge.kind == "imports")
30
+ define_edges = sum(1 for edge in graph.edges if edge.kind == "defines")
31
+
32
+ summary = [
33
+ f"Project root: {self.project_root}",
34
+ f"Graph nodes: {len(graph.nodes)}",
35
+ f"Graph edges: {len(graph.edges)}",
36
+ f"Files: {counts.get('file', 0)}",
37
+ f"Symbols: {define_edges}",
38
+ f"Import relationships: {import_edges}",
39
+ ]
40
+ if matches:
41
+ summary.append(
42
+ "Relevant graph nodes:\n"
43
+ + "\n".join(
44
+ f"- {node.kind}: {node.name}"
45
+ + (f" ({node.path}:{node.line or 1})" if node.path else "")
46
+ for node in matches
47
+ )
48
+ )
49
+
50
+ content = "\n".join(summary)
51
+ return EngineResult(
52
+ capability=self.capability,
53
+ content=content,
54
+ chunks=[
55
+ ContextChunk(
56
+ source="repository-graph",
57
+ content=content,
58
+ tokens=max(1, len(content) // 4),
59
+ relevance=0.85,
60
+ metadata={
61
+ "nodes": len(graph.nodes),
62
+ "edges": len(graph.edges),
63
+ "matches": len(matches),
64
+ },
65
+ )
66
+ ],
67
+ metadata={
68
+ "nodes": len(graph.nodes),
69
+ "edges": len(graph.edges),
70
+ "node_counts": counts,
71
+ "graph_path": str(graph_path),
72
+ },
73
+ )
@@ -0,0 +1,89 @@
1
+ """Local multi-language symbol intelligence engine."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from codecortex.core.contracts import Engine
8
+ from codecortex.core.models import AgentRequest, Capability, ContextChunk, EngineResult
9
+ from codecortex.symbols import SymbolProviderRegistry, SymbolRecord
10
+
11
+ _EXCLUDED = {".git", ".codecortex", ".venv", "venv", "node_modules", "__pycache__"}
12
+
13
+
14
+ class SymbolEngine(Engine):
15
+ capability = Capability.SYMBOLS
16
+
17
+ def __init__(self, project_root: Path, max_files: int = 5_000) -> None:
18
+ self.project_root = project_root.resolve()
19
+ self.max_files = max_files
20
+ self.providers = SymbolProviderRegistry()
21
+
22
+ async def health(self) -> bool:
23
+ return self.project_root.exists() and self.project_root.is_dir()
24
+
25
+ def _symbols(self) -> list[SymbolRecord]:
26
+ symbols: list[SymbolRecord] = []
27
+ count = 0
28
+ for path in self.project_root.rglob("*"):
29
+ if count >= self.max_files:
30
+ break
31
+ if not path.is_file() or not self.providers.supports(path):
32
+ continue
33
+ relative = path.relative_to(self.project_root)
34
+ if any(part in _EXCLUDED for part in relative.parts):
35
+ continue
36
+ count += 1
37
+ try:
38
+ source = path.read_text(encoding="utf-8")
39
+ except (OSError, UnicodeDecodeError):
40
+ continue
41
+ symbols.extend(self.providers.extract(path, source))
42
+ return symbols
43
+
44
+ async def execute(self, request: AgentRequest) -> EngineResult:
45
+ symbols = self._symbols()
46
+ terms = {
47
+ term.lower().strip(".,:;()[]{}")
48
+ for term in request.query.split()
49
+ if len(term) > 2
50
+ }
51
+ ranked: list[tuple[int, SymbolRecord]] = []
52
+ for symbol in symbols:
53
+ name = symbol.name.lower()
54
+ path = str(symbol.path.relative_to(self.project_root)).lower()
55
+ score = sum(
56
+ 5 if term == name else 3 if term in name else 1 if term in path else 0
57
+ for term in terms
58
+ )
59
+ if score:
60
+ ranked.append((score, symbol))
61
+ ranked.sort(key=lambda item: (-item[0], item[1].line, item[1].name))
62
+ matches = [symbol for _, symbol in ranked[:50]]
63
+ lines = [
64
+ (
65
+ f"{symbol.language}:{symbol.kind} {symbol.name} — "
66
+ f"{symbol.path.relative_to(self.project_root)}:{symbol.line}"
67
+ )
68
+ for symbol in matches
69
+ ]
70
+ content = "\n".join(lines) if lines else "No matching symbols found."
71
+ languages = sorted({symbol.language for symbol in symbols})
72
+ return EngineResult(
73
+ capability=self.capability,
74
+ content=content,
75
+ chunks=[
76
+ ContextChunk(
77
+ source="symbol-index",
78
+ content=content,
79
+ tokens=max(1, len(content) // 4),
80
+ relevance=0.90 if matches else 0.30,
81
+ metadata={"matches": len(matches), "languages": languages},
82
+ )
83
+ ],
84
+ metadata={
85
+ "symbols_indexed": len(symbols),
86
+ "matches": len(matches),
87
+ "languages": languages,
88
+ },
89
+ )
@@ -0,0 +1,54 @@
1
+ """Local validation engine."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import ast
6
+ from pathlib import Path
7
+
8
+ from codecortex.core.contracts import Engine
9
+ from codecortex.core.models import AgentRequest, Capability, ContextChunk, EngineResult
10
+
11
+
12
+ class ValidationEngine(Engine):
13
+ capability = Capability.VALIDATION
14
+
15
+ def __init__(self, project_root: Path, max_files: int = 2_000) -> None:
16
+ self.project_root = project_root.resolve()
17
+ self.max_files = max_files
18
+
19
+ async def health(self) -> bool:
20
+ return self.project_root.exists() and self.project_root.is_dir()
21
+
22
+ async def execute(self, request: AgentRequest) -> EngineResult:
23
+ del request
24
+ checked = 0
25
+ issues: list[str] = []
26
+ for path in self.project_root.rglob("*.py"):
27
+ if checked >= self.max_files:
28
+ break
29
+ if any(part in {".git", ".codecortex", ".venv", "venv", "__pycache__"} for part in path.parts):
30
+ continue
31
+ checked += 1
32
+ try:
33
+ ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
34
+ except SyntaxError as exc:
35
+ relative = path.relative_to(self.project_root)
36
+ issues.append(f"{relative}:{exc.lineno}: {exc.msg}")
37
+ except (OSError, UnicodeDecodeError):
38
+ continue
39
+
40
+ content = "Python syntax validation passed." if not issues else "\n".join(issues[:100])
41
+ return EngineResult(
42
+ capability=self.capability,
43
+ content=content,
44
+ chunks=[
45
+ ContextChunk(
46
+ source="validation",
47
+ content=content,
48
+ tokens=max(1, len(content) // 4),
49
+ relevance=0.95,
50
+ metadata={"issues": len(issues), "checked": checked},
51
+ )
52
+ ],
53
+ metadata={"checked": checked, "issues": len(issues)},
54
+ )
@@ -0,0 +1,26 @@
1
+ """Capability-based engine registry."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from codecortex.core.contracts import Engine
6
+ from codecortex.core.models import Capability
7
+
8
+
9
+ class EngineRegistry:
10
+ def __init__(self) -> None:
11
+ self._engines: dict[Capability, Engine] = {}
12
+
13
+ def register(self, engine: Engine) -> None:
14
+ self._engines[engine.capability] = engine
15
+
16
+ def get(self, capability: Capability) -> Engine | None:
17
+ return self._engines.get(capability)
18
+
19
+ def capabilities(self) -> list[Capability]:
20
+ return list(self._engines)
21
+
22
+ async def health(self) -> dict[Capability, bool]:
23
+ result: dict[Capability, bool] = {}
24
+ for capability, engine in self._engines.items():
25
+ result[capability] = await engine.health()
26
+ return result
@@ -0,0 +1,266 @@
1
+ """Extended public CLI surface for packaging, backends, agent setup, and edits."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import asdict
6
+ from importlib.metadata import PackageNotFoundError, version
7
+ from pathlib import Path
8
+ from typing import Annotated
9
+
10
+ import typer
11
+ from rich.console import Console
12
+ from rich.table import Table
13
+
14
+ import codecortex.cli as cli_module
15
+ from codecortex.backends import (
16
+ BACKENDS,
17
+ BackendManager,
18
+ ContextBackendAdapter,
19
+ GraphBackendAdapter,
20
+ SymbolBackendAdapter,
21
+ )
22
+ from codecortex.cli import app
23
+ from codecortex.editing import EditService
24
+ from codecortex.integrations import AgentConfigurator, AgentTarget
25
+ from codecortex.mcp.extended import run_stdio as extended_run_stdio
26
+ from codecortex.runtime import build_runtime
27
+ from codecortex.setup import ProjectSetup
28
+
29
+ cli_module.run_stdio = extended_run_stdio
30
+
31
+ console = Console()
32
+ backend_app = typer.Typer(help="Install and inspect isolated intelligence backends.")
33
+ agents_app = typer.Typer(help="Detect and configure coding-agent integrations.")
34
+ edit_app = typer.Typer(help="Perform guarded language-server semantic edits.")
35
+ app.add_typer(backend_app, name="backend")
36
+ app.add_typer(agents_app, name="agents")
37
+ app.add_typer(edit_app, name="edit")
38
+
39
+
40
+ def _manager() -> BackendManager:
41
+ return BackendManager(timeout_seconds=1200)
42
+
43
+
44
+ def _targets(value: str) -> tuple[str, ...]:
45
+ if value == "all":
46
+ return tuple(BACKENDS)
47
+ if value not in BACKENDS:
48
+ raise typer.BadParameter(f"expected one of: all, {', '.join(BACKENDS)}")
49
+ return (value,)
50
+
51
+
52
+ def _adapter(key: str, root: Path, manager: BackendManager):
53
+ if key == "graph":
54
+ return GraphBackendAdapter(root, manager)
55
+ if key == "symbols":
56
+ return SymbolBackendAdapter(root, manager)
57
+ if key == "context":
58
+ return ContextBackendAdapter(root, manager)
59
+ raise KeyError(key)
60
+
61
+
62
+ def _edit_service(path: Path) -> EditService:
63
+ return EditService(build_runtime(path.expanduser().resolve()))
64
+
65
+
66
+ @app.command("version")
67
+ def version_command() -> None:
68
+ try:
69
+ current = version("codecortex-context-engine")
70
+ except PackageNotFoundError:
71
+ current = "0+unknown"
72
+ console.print(current)
73
+
74
+
75
+ @backend_app.command("list")
76
+ def backend_list() -> None:
77
+ manager = _manager()
78
+ table = Table(title="CodeCortex Backends")
79
+ table.add_column("Backend")
80
+ table.add_column("Installed")
81
+ table.add_column("Revision")
82
+ table.add_column("Capabilities")
83
+ for key, spec in BACKENDS.items():
84
+ table.add_row(
85
+ key,
86
+ "yes" if manager.is_installed(spec) else "no",
87
+ spec.revision[:12],
88
+ ", ".join(spec.capabilities),
89
+ )
90
+ console.print(table)
91
+
92
+
93
+ @backend_app.command("install")
94
+ def backend_install(
95
+ target: Annotated[str, typer.Argument(help="graph, symbols, context, or all")] = "all",
96
+ ) -> None:
97
+ manager = _manager()
98
+ failures: list[str] = []
99
+ for key in _targets(target):
100
+ spec = BACKENDS[key]
101
+ console.print(f"Installing [bold]{key}[/bold] at {spec.revision[:12]}…")
102
+ try:
103
+ command = manager.ensure(spec)
104
+ console.print(f"[green]✓[/green] {key}: {command}")
105
+ except Exception as exc:
106
+ failures.append(key)
107
+ console.print(f"[red]✗[/red] {key}: {type(exc).__name__}: {exc}")
108
+ if failures:
109
+ raise typer.Exit(code=2)
110
+
111
+
112
+ @backend_app.command("doctor")
113
+ def backend_doctor(
114
+ path: Annotated[Path, typer.Option("--path", "-p")] = Path("."),
115
+ ) -> None:
116
+ root = path.expanduser().resolve()
117
+ manager = _manager()
118
+ table = Table(title="Backend Health")
119
+ table.add_column("Backend")
120
+ table.add_column("Installed")
121
+ table.add_column("Healthy")
122
+ table.add_column("Contract")
123
+ failed = False
124
+ for key in BACKENDS:
125
+ adapter = _adapter(key, root, manager)
126
+ status = adapter.status()
127
+ table.add_row(
128
+ key,
129
+ "yes" if status.installed else "no",
130
+ "yes" if status.healthy else "no",
131
+ f"v{status.contract_version}",
132
+ )
133
+ if status.installed and not status.healthy:
134
+ failed = True
135
+ console.print(table)
136
+ if failed:
137
+ raise typer.Exit(code=2)
138
+
139
+
140
+ @backend_app.command("remove")
141
+ def backend_remove(
142
+ target: Annotated[str, typer.Argument(help="graph, symbols, context, or all")],
143
+ ) -> None:
144
+ manager = _manager()
145
+ for key in _targets(target):
146
+ manager.remove(BACKENDS[key])
147
+ console.print(f"[green]Removed[/green] {key}")
148
+
149
+
150
+ @agents_app.command("detect")
151
+ def agents_detect(
152
+ path: Annotated[Path, typer.Option("--path", "-p")] = Path("."),
153
+ ) -> None:
154
+ found = AgentConfigurator(path).detect()
155
+ if not found:
156
+ console.print("No supported coding agents detected.")
157
+ return
158
+ for target in found:
159
+ console.print(target.value)
160
+
161
+
162
+ @agents_app.command("configure")
163
+ def agents_configure(
164
+ path: Annotated[Path, typer.Option("--path", "-p")] = Path("."),
165
+ target: Annotated[list[AgentTarget] | None, typer.Option("--target", "-t")] = None,
166
+ all_supported: Annotated[bool, typer.Option("--all")] = False,
167
+ dry_run: Annotated[bool, typer.Option("--dry-run")] = False,
168
+ ) -> None:
169
+ configurator = AgentConfigurator(path)
170
+ selected = tuple(AgentTarget) if all_supported else tuple(target or configurator.detect())
171
+ mutations = configurator.configure(selected, dry_run=dry_run)
172
+ for item in mutations:
173
+ state = (
174
+ "would update"
175
+ if dry_run and item.changed
176
+ else "updated"
177
+ if item.changed
178
+ else "unchanged"
179
+ )
180
+ console.print(f"{item.target.value}: {state} {item.path}")
181
+ if item.backup:
182
+ console.print(f" backup: {item.backup}")
183
+
184
+
185
+ @edit_app.command("rename")
186
+ def edit_rename(
187
+ relative_path: Annotated[str, typer.Argument(help="Repository-relative file")],
188
+ name_path: Annotated[str, typer.Argument(help="Semantic symbol name path")],
189
+ new_name: Annotated[str, typer.Argument(help="New symbol name")],
190
+ path: Annotated[Path, typer.Option("--path", "-p")] = Path("."),
191
+ ) -> None:
192
+ console.print_json(data=_edit_service(path).rename(relative_path, name_path, new_name))
193
+
194
+
195
+ @edit_app.command("replace")
196
+ def edit_replace(
197
+ relative_path: Annotated[str, typer.Argument()],
198
+ name_path: Annotated[str, typer.Argument()],
199
+ body_file: Annotated[Path, typer.Option("--body-file")],
200
+ path: Annotated[Path, typer.Option("--path", "-p")] = Path("."),
201
+ ) -> None:
202
+ body = body_file.read_text(encoding="utf-8")
203
+ console.print_json(data=_edit_service(path).replace(relative_path, name_path, body))
204
+
205
+
206
+ @edit_app.command("insert-before")
207
+ def edit_insert_before(
208
+ relative_path: Annotated[str, typer.Argument()],
209
+ name_path: Annotated[str, typer.Argument()],
210
+ body_file: Annotated[Path, typer.Option("--body-file")],
211
+ path: Annotated[Path, typer.Option("--path", "-p")] = Path("."),
212
+ ) -> None:
213
+ body = body_file.read_text(encoding="utf-8")
214
+ console.print_json(data=_edit_service(path).insert_before(relative_path, name_path, body))
215
+
216
+
217
+ @edit_app.command("insert-after")
218
+ def edit_insert_after(
219
+ relative_path: Annotated[str, typer.Argument()],
220
+ name_path: Annotated[str, typer.Argument()],
221
+ body_file: Annotated[Path, typer.Option("--body-file")],
222
+ path: Annotated[Path, typer.Option("--path", "-p")] = Path("."),
223
+ ) -> None:
224
+ body = body_file.read_text(encoding="utf-8")
225
+ console.print_json(data=_edit_service(path).insert_after(relative_path, name_path, body))
226
+
227
+
228
+ @app.command("bootstrap")
229
+ def bootstrap(
230
+ path: Annotated[Path, typer.Option("--path", "-p")] = Path("."),
231
+ install_backends: Annotated[bool, typer.Option("--backends/--no-backends")] = True,
232
+ configure_agents: Annotated[bool, typer.Option("--agents/--no-agents")] = True,
233
+ strict: Annotated[bool, typer.Option("--strict")] = False,
234
+ ) -> None:
235
+ root = path.expanduser().resolve()
236
+ result = ProjectSetup(root).run()
237
+ console.print(
238
+ f"Core ready: {result.index.tracked} files, {result.symbols} symbols, "
239
+ f"{result.graph_nodes} graph nodes."
240
+ )
241
+ failures: list[str] = []
242
+ if install_backends:
243
+ manager = _manager()
244
+ for key, spec in BACKENDS.items():
245
+ try:
246
+ manager.ensure(spec)
247
+ console.print(f"[green]✓[/green] backend {key}")
248
+ except Exception as exc:
249
+ failures.append(key)
250
+ console.print(f"[yellow]![/yellow] backend {key}: {type(exc).__name__}: {exc}")
251
+ if configure_agents:
252
+ configurator = AgentConfigurator(root)
253
+ for mutation in configurator.configure():
254
+ console.print(f"[green]✓[/green] agent {mutation.target.value}: {mutation.path}")
255
+ if strict and failures:
256
+ raise typer.Exit(code=2)
257
+
258
+
259
+ @app.command("backend-status")
260
+ def backend_status(
261
+ path: Annotated[Path, typer.Option("--path", "-p")] = Path("."),
262
+ ) -> None:
263
+ root = path.expanduser().resolve()
264
+ manager = _manager()
265
+ payload = {key: asdict(_adapter(key, root, manager).status()) for key in BACKENDS}
266
+ console.print_json(data=payload)
@@ -0,0 +1,55 @@
1
+ """Benchmark and external evaluation infrastructure."""
2
+
3
+ from codecortex.evaluation.external import (
4
+ DeterministicGrader,
5
+ EvaluationCase,
6
+ EvaluationExpectation,
7
+ EvaluationOutput,
8
+ EvaluationReport,
9
+ ExternalEvaluationSuite,
10
+ SubprocessEvaluationTarget,
11
+ )
12
+ from codecortex.evaluation.production import (
13
+ AgentProtocolResult,
14
+ BenchmarkCaseSpec,
15
+ InstrumentedAgentRunner,
16
+ ObservedMetrics,
17
+ ProductionBenchmarkReport,
18
+ ProductionBenchmarkRunner,
19
+ RepositorySpec,
20
+ ScenarioResult,
21
+ SetupMeasurement,
22
+ load_repository_specs,
23
+ )
24
+ from codecortex.evaluation.regression import (
25
+ BenchmarkHistory,
26
+ BenchmarkSnapshot,
27
+ GateReport,
28
+ MetricPolicy,
29
+ RegressionGate,
30
+ )
31
+
32
+ __all__ = [
33
+ "AgentProtocolResult",
34
+ "BenchmarkCaseSpec",
35
+ "BenchmarkHistory",
36
+ "BenchmarkSnapshot",
37
+ "DeterministicGrader",
38
+ "EvaluationCase",
39
+ "EvaluationExpectation",
40
+ "EvaluationOutput",
41
+ "EvaluationReport",
42
+ "ExternalEvaluationSuite",
43
+ "GateReport",
44
+ "InstrumentedAgentRunner",
45
+ "MetricPolicy",
46
+ "ObservedMetrics",
47
+ "ProductionBenchmarkReport",
48
+ "ProductionBenchmarkRunner",
49
+ "RegressionGate",
50
+ "RepositorySpec",
51
+ "ScenarioResult",
52
+ "SetupMeasurement",
53
+ "SubprocessEvaluationTarget",
54
+ "load_repository_specs",
55
+ ]