codegraph-engine 3.0.0__2-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 (130) hide show
  1. codegraph/__init__.py +37 -0
  2. codegraph/agent.py +26 -0
  3. codegraph/agent_brain.py +2212 -0
  4. codegraph/agent_capabilities.py +4058 -0
  5. codegraph/agent_rules.py +531 -0
  6. codegraph/api_drift.py +455 -0
  7. codegraph/architecture.py +371 -0
  8. codegraph/async_queue/__init__.py +50 -0
  9. codegraph/async_queue/detectors/__init__.py +48 -0
  10. codegraph/async_queue/detectors/celery.py +160 -0
  11. codegraph/async_queue/detectors/kafka.py +168 -0
  12. codegraph/async_queue/detectors/rabbitmq.py +116 -0
  13. codegraph/async_queue/detectors/redis.py +130 -0
  14. codegraph/async_queue/detectors/sqs.py +135 -0
  15. codegraph/async_queue/models.py +161 -0
  16. codegraph/async_queue/otel_models.py +74 -0
  17. codegraph/async_queue/otel_parser.py +337 -0
  18. codegraph/async_queue/reconciler.py +427 -0
  19. codegraph/async_queue/scanner.py +291 -0
  20. codegraph/async_queue/traversal.py +447 -0
  21. codegraph/audit.py +106 -0
  22. codegraph/binding_resolver.py +616 -0
  23. codegraph/branch_comparison.py +197 -0
  24. codegraph/cache.py +95 -0
  25. codegraph/change_impact.py +547 -0
  26. codegraph/cli.py +2436 -0
  27. codegraph/cli_output.py +205 -0
  28. codegraph/config.py +45 -0
  29. codegraph/constraints.py +238 -0
  30. codegraph/context.py +2182 -0
  31. codegraph/context_freshness.py +351 -0
  32. codegraph/database/__init__.py +72 -0
  33. codegraph/database/extractor.py +3651 -0
  34. codegraph/database/interrogation.py +1494 -0
  35. codegraph/database/models.py +310 -0
  36. codegraph/database/schema_drift.py +862 -0
  37. codegraph/epistemic.py +200 -0
  38. codegraph/errors.py +282 -0
  39. codegraph/evidence/__init__.py +15 -0
  40. codegraph/evidence/citations.py +418 -0
  41. codegraph/evidence_contract.py +486 -0
  42. codegraph/frameworks.py +960 -0
  43. codegraph/frameworks_nestjs.py +502 -0
  44. codegraph/frameworks_nextjs.py +337 -0
  45. codegraph/frameworks_react.py +457 -0
  46. codegraph/freshness.py +335 -0
  47. codegraph/frontend_html.py +109 -0
  48. codegraph/git.py +362 -0
  49. codegraph/git_state.py +545 -0
  50. codegraph/graph/__init__.py +46 -0
  51. codegraph/graph/models.py +56 -0
  52. codegraph/graph/traversal.py +1993 -0
  53. codegraph/indexing/__init__.py +24 -0
  54. codegraph/indexing/classifier.py +564 -0
  55. codegraph/indexing/indexer.py +2578 -0
  56. codegraph/indexing/models.py +427 -0
  57. codegraph/indexing/parser.py +3404 -0
  58. codegraph/indexing/pool.py +136 -0
  59. codegraph/indexing/scanner.py +211 -0
  60. codegraph/indexing/telemetry.py +326 -0
  61. codegraph/indexing/templates.py +418 -0
  62. codegraph/indexing/test_framework.py +116 -0
  63. codegraph/installer.py +1702 -0
  64. codegraph/interrogation.py +2355 -0
  65. codegraph/llm/__init__.py +3 -0
  66. codegraph/llm/base.py +15 -0
  67. codegraph/llm/context.py +20 -0
  68. codegraph/mcp/__init__.py +3 -0
  69. codegraph/mcp/server.py +1476 -0
  70. codegraph/mcp_diagnostics.py +882 -0
  71. codegraph/memory/__init__.py +3 -0
  72. codegraph/memory/store.py +46 -0
  73. codegraph/models.py +310 -0
  74. codegraph/monorepo.py +925 -0
  75. codegraph/observability.py +262 -0
  76. codegraph/optimizer.py +1014 -0
  77. codegraph/planner.py +417 -0
  78. codegraph/process_lifecycle.py +1153 -0
  79. codegraph/py.typed +1 -0
  80. codegraph/query_expansion.py +199 -0
  81. codegraph/ranking.py +408 -0
  82. codegraph/refactor/__init__.py +36 -0
  83. codegraph/refactor/models.py +114 -0
  84. codegraph/refactor/renamer.py +844 -0
  85. codegraph/refactor/transactions.py +414 -0
  86. codegraph/resolver.py +3968 -0
  87. codegraph/resources/__init__.py +46 -0
  88. codegraph/resources/cache.py +117 -0
  89. codegraph/resources/coalescer.py +83 -0
  90. codegraph/resources/debouncer.py +98 -0
  91. codegraph/resources/governor.py +219 -0
  92. codegraph/resources/monitor.py +102 -0
  93. codegraph/resources/policy.py +123 -0
  94. codegraph/retrieval_policy.py +320 -0
  95. codegraph/roblox.py +2174 -0
  96. codegraph/route_composer.py +363 -0
  97. codegraph/route_topology.py +172 -0
  98. codegraph/runtime/__init__.py +51 -0
  99. codegraph/runtime/collector.py +155 -0
  100. codegraph/runtime/db_watcher.py +191 -0
  101. codegraph/runtime/ingestor.py +692 -0
  102. codegraph/runtime/models.py +130 -0
  103. codegraph/runtime/port_inspector.py +304 -0
  104. codegraph/runtime/reconciliation.py +492 -0
  105. codegraph/runtime/runner.py +353 -0
  106. codegraph/runtime/trace_linker.py +175 -0
  107. codegraph/search/__init__.py +25 -0
  108. codegraph/search/hybrid.py +846 -0
  109. codegraph/search/semantic.py +28 -0
  110. codegraph/security/__init__.py +51 -0
  111. codegraph/security/paths.py +189 -0
  112. codegraph/security/redaction.py +633 -0
  113. codegraph/semantic_conflicts.py +270 -0
  114. codegraph/semantic_decorators.py +372 -0
  115. codegraph/structural_diff.py +542 -0
  116. codegraph/styles.py +144 -0
  117. codegraph/symbol_history.py +277 -0
  118. codegraph/target_resolver.py +348 -0
  119. codegraph/task.py +637 -0
  120. codegraph/tool_selection_eval.py +1158 -0
  121. codegraph/tsconfig.py +236 -0
  122. codegraph/ui/__init__.py +6 -0
  123. codegraph/ui/server.py +755 -0
  124. codegraph/watcher.py +323 -0
  125. codegraph_engine-3.0.0.dist-info/METADATA +868 -0
  126. codegraph_engine-3.0.0.dist-info/RECORD +130 -0
  127. codegraph_engine-3.0.0.dist-info/WHEEL +6 -0
  128. codegraph_engine-3.0.0.dist-info/entry_points.txt +2 -0
  129. codegraph_engine-3.0.0.dist-info/licenses/LICENSE +21 -0
  130. codegraph_engine-3.0.0.dist-info/top_level.txt +1 -0
codegraph/planner.py ADDED
@@ -0,0 +1,417 @@
1
+ """Deterministic Retrieval Planner for CodeGraph MCP.
2
+
3
+ Translates a grounded TaskSpec into an intent-driven, deterministic RetrievalPlan.
4
+ Query groups distinguish between primary targets, callers, callees, dependencies,
5
+ tests, git changes, framework routes, and architecture slices without guessing.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import hashlib
10
+ import json
11
+ import sqlite3
12
+ from dataclasses import asdict, dataclass
13
+
14
+ from codegraph.task import AmbiguityStatus, TaskAmbiguity, TaskIntent, TaskSpec
15
+
16
+ PLAN_SCHEMA_VERSION = "1.0"
17
+
18
+
19
+ class QueryPurpose:
20
+ PRIMARY_TARGET = "PRIMARY_TARGET"
21
+ ENTRY_POINT = "ENTRY_POINT"
22
+ RELATED_SYMBOLS = "RELATED_SYMBOLS"
23
+ CALLERS = "CALLERS"
24
+ CALLEES = "CALLEES"
25
+ DEPENDENCIES = "DEPENDENCIES"
26
+ IMPLEMENTATIONS = "IMPLEMENTATIONS"
27
+ TESTS = "TESTS"
28
+ FRAMEWORK = "FRAMEWORK"
29
+ GIT = "GIT"
30
+ ARCHITECTURE = "ARCHITECTURE"
31
+
32
+
33
+ @dataclass(frozen=True)
34
+ class QueryGroup:
35
+ purpose: str
36
+ queries: tuple[str, ...]
37
+ weight: float = 1.0
38
+ required: bool = True
39
+
40
+ def as_dict(self) -> dict[str, object]:
41
+ return asdict(self)
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class RetrievalPlan:
46
+ schema_version: str = PLAN_SCHEMA_VERSION
47
+ task_spec_hash: str = ""
48
+ task_fingerprint: str = ""
49
+ intent: str = ""
50
+
51
+ query_groups: tuple[QueryGroup, ...] = ()
52
+
53
+ required_relationships: tuple[str, ...] = ()
54
+ optional_relationships: tuple[str, ...] = ()
55
+
56
+ include_tests: bool = True
57
+ include_git: bool = False
58
+ include_framework: bool = True
59
+ include_architecture: bool = False
60
+
61
+ entry_point_strategy: str = "DIRECT" # DIRECT | TRACE_FROM_ENDPOINT | TRACE_HIERARCHY | GIT_DIFF_ENTRY
62
+
63
+ max_depth: int = 3
64
+ max_nodes: int = 300
65
+ max_edges: int = 1200
66
+ token_budget: int = 20_000
67
+
68
+ freshness_policy: str = "REQUIRE_FRESH" # REQUIRE_FRESH | PERMIT_PARTIAL | BEST_EFFORT
69
+ evidence_policy: str = "VERIFY_SOURCE_HASH"
70
+ ambiguity_policy: str = "REPORT_OR_ASSUME" # REPORT_OR_ASSUME | STRICT_FAIL | BEST_EFFORT
71
+
72
+ def as_dict(self) -> dict[str, object]:
73
+ return {
74
+ "schema_version": self.schema_version,
75
+ "task_spec_hash": self.task_spec_hash or self.task_fingerprint,
76
+ "task_fingerprint": self.task_fingerprint or self.task_spec_hash,
77
+ "intent": self.intent,
78
+ "query_groups": [q.as_dict() for q in self.query_groups],
79
+ "required_relationships": list(self.required_relationships),
80
+ "optional_relationships": list(self.optional_relationships),
81
+ "include_tests": self.include_tests,
82
+ "include_git": self.include_git,
83
+ "include_framework": self.include_framework,
84
+ "include_architecture": self.include_architecture,
85
+ "entry_point_strategy": self.entry_point_strategy,
86
+ "max_depth": self.max_depth,
87
+ "max_nodes": self.max_nodes,
88
+ "max_edges": self.max_edges,
89
+ "token_budget": self.token_budget,
90
+ "freshness_policy": self.freshness_policy,
91
+ "evidence_policy": self.evidence_policy,
92
+ "ambiguity_policy": self.ambiguity_policy,
93
+ }
94
+
95
+
96
+ def compute_task_spec_hash(task_spec: TaskSpec) -> str:
97
+ """Compute a deterministic SHA-256 hash of a TaskSpec."""
98
+ canonical_payload = {
99
+ "intent": task_spec.intent,
100
+ "goal": task_spec.goal,
101
+ "targets": sorted(task_spec.targets),
102
+ "entities": sorted(task_spec.entities),
103
+ "operations": sorted(task_spec.operations),
104
+ "constraints": sorted(task_spec.constraints),
105
+ "exclusions": sorted(task_spec.exclusions),
106
+ "scope_paths": sorted(task_spec.scope_paths),
107
+ "scope_modules": sorted(task_spec.scope_modules),
108
+ "frameworks": sorted(task_spec.frameworks),
109
+ "time_scope": task_spec.time_scope or "",
110
+ }
111
+ raw_bytes = json.dumps(canonical_payload, sort_keys=True, separators=(",", ":")).encode("utf-8")
112
+ return hashlib.sha256(raw_bytes).hexdigest()[:16]
113
+
114
+
115
+ def build_retrieval_plan(
116
+ task_spec: TaskSpec,
117
+ ambiguities: tuple[TaskAmbiguity, ...] = (),
118
+ con: sqlite3.Connection | None = None,
119
+ token_budget: int = 20_000,
120
+ resource_mode: str = "BALANCED",
121
+ ) -> RetrievalPlan:
122
+ """Construct an intent-specific, repository-aware RetrievalPlan for a TaskSpec."""
123
+ spec_hash = compute_task_spec_hash(task_spec)
124
+ intent = task_spec.intent.upper()
125
+
126
+ # Base query items from targets
127
+ primary_queries = tuple(task_spec.priority_targets or task_spec.targets or (task_spec.goal,))
128
+ related_queries: list[str] = []
129
+
130
+ if con and primary_queries:
131
+ from codegraph.query_expansion import expand_query_terms, get_search_queries
132
+
133
+ expansions = expand_query_terms(primary_queries[:5], con, max_expansions=8)
134
+ expanded_terms = get_search_queries(expansions)
135
+ for term in expanded_terms:
136
+ if term not in primary_queries and term not in related_queries:
137
+ related_queries.append(term)
138
+
139
+ query_groups: list[QueryGroup] = []
140
+
141
+ # Primary target group
142
+ query_groups.append(
143
+ QueryGroup(
144
+ purpose=QueryPurpose.PRIMARY_TARGET,
145
+ queries=primary_queries,
146
+ weight=1.0,
147
+ required=True,
148
+ )
149
+ )
150
+
151
+ if related_queries:
152
+ query_groups.append(
153
+ QueryGroup(
154
+ purpose=QueryPurpose.RELATED_SYMBOLS,
155
+ queries=tuple(related_queries[:8]),
156
+ weight=0.75,
157
+ required=False,
158
+ )
159
+ )
160
+
161
+ # Strategy configuration based on intent
162
+ include_tests = True
163
+ include_git = False
164
+ include_framework = True
165
+ include_architecture = False
166
+ entry_point_strategy = "DIRECT"
167
+ max_depth = 3
168
+ required_relationships: list[str] = []
169
+ optional_relationships: list[str] = ["CALLS", "IMPORTS"]
170
+
171
+ # Check explicit time_scope or operations in TaskSpec
172
+ if task_spec.time_scope or "INSPECT_RECENT_CHANGES" in task_spec.operations:
173
+ include_git = True
174
+
175
+ # Adaptive depth calculation based on query complexity and resource mode
176
+ goal_lower = (task_spec.goal or "").lower()
177
+ is_shallow = any(pattern in goal_lower for pattern in ("where is", "where's", "find definition", "show definition", "locate"))
178
+ mode_upper = (resource_mode or "BALANCED").upper()
179
+
180
+ if is_shallow:
181
+ max_depth = 1
182
+ elif mode_upper == "FAST":
183
+ max_depth = min(max_depth, 2)
184
+ elif mode_upper == "DEEP":
185
+ max_depth = max(max_depth, 5)
186
+
187
+ if mode_upper == "FAST":
188
+ max_nodes = 100
189
+ max_edges = 400
190
+ elif mode_upper == "DEEP":
191
+ max_nodes = 600
192
+ max_edges = 2400
193
+ else:
194
+ max_nodes = 300
195
+ max_edges = 1200
196
+
197
+ if intent in (TaskIntent.UNDERSTAND.value, TaskIntent.EXPLAIN.value):
198
+ include_architecture = True
199
+ required_relationships = ["HANDLED_BY", "CALLS"]
200
+ optional_relationships = ["IMPORTS", "EXTENDS"]
201
+ query_groups.append(
202
+ QueryGroup(
203
+ purpose=QueryPurpose.ARCHITECTURE,
204
+ queries=primary_queries[:3],
205
+ weight=0.6,
206
+ required=False,
207
+ )
208
+ )
209
+ query_groups.append(
210
+ QueryGroup(
211
+ purpose=QueryPurpose.TESTS,
212
+ queries=primary_queries[:3],
213
+ weight=0.5,
214
+ required=False,
215
+ )
216
+ )
217
+
218
+ elif intent == TaskIntent.DEBUG.value:
219
+ include_git = True
220
+ entry_point_strategy = "TRACE_FROM_ENDPOINT"
221
+ max_depth = 3
222
+ required_relationships = ["HANDLED_BY", "CALLS"]
223
+ optional_relationships = ["IMPORTS", "EXTENDS", "POSSIBLE_CALLS"]
224
+ query_groups.append(
225
+ QueryGroup(
226
+ purpose=QueryPurpose.CALLERS,
227
+ queries=primary_queries[:4],
228
+ weight=0.85,
229
+ required=True,
230
+ )
231
+ )
232
+ query_groups.append(
233
+ QueryGroup(
234
+ purpose=QueryPurpose.TESTS,
235
+ queries=primary_queries[:3],
236
+ weight=0.7,
237
+ required=True,
238
+ )
239
+ )
240
+ if include_git:
241
+ query_groups.append(
242
+ QueryGroup(
243
+ purpose=QueryPurpose.GIT,
244
+ queries=primary_queries[:3],
245
+ weight=0.8,
246
+ required=False,
247
+ )
248
+ )
249
+
250
+ elif intent in (TaskIntent.CHANGE.value, TaskIntent.REFACTOR.value):
251
+ entry_point_strategy = "DIRECT"
252
+ max_depth = 2
253
+ required_relationships = ["CALLS"]
254
+ optional_relationships = ["EXTENDS", "IMPLEMENTS", "IMPORTS"]
255
+ query_groups.append(
256
+ QueryGroup(
257
+ purpose=QueryPurpose.CALLERS,
258
+ queries=primary_queries[:4],
259
+ weight=0.9,
260
+ required=True,
261
+ )
262
+ )
263
+ query_groups.append(
264
+ QueryGroup(
265
+ purpose=QueryPurpose.CALLEES,
266
+ queries=primary_queries[:4],
267
+ weight=0.85,
268
+ required=True,
269
+ )
270
+ )
271
+ query_groups.append(
272
+ QueryGroup(
273
+ purpose=QueryPurpose.TESTS,
274
+ queries=primary_queries[:3],
275
+ weight=0.75,
276
+ required=True,
277
+ )
278
+ )
279
+
280
+ elif intent == TaskIntent.TRACE.value:
281
+ entry_point_strategy = "TRACE_HIERARCHY"
282
+ max_depth = 4
283
+ required_relationships = ["HANDLED_BY", "CALLS"]
284
+ optional_relationships = ["IMPORTS"]
285
+ query_groups.append(
286
+ QueryGroup(
287
+ purpose=QueryPurpose.FRAMEWORK,
288
+ queries=primary_queries[:4],
289
+ weight=0.95,
290
+ required=True,
291
+ )
292
+ )
293
+ query_groups.append(
294
+ QueryGroup(
295
+ purpose=QueryPurpose.CALLEES,
296
+ queries=primary_queries[:4],
297
+ weight=0.9,
298
+ required=True,
299
+ )
300
+ )
301
+
302
+ elif intent == TaskIntent.IMPACT.value:
303
+ entry_point_strategy = "DIRECT"
304
+ max_depth = 4
305
+ include_architecture = True
306
+ required_relationships = ["CALLS", "IMPORTS"]
307
+ optional_relationships = ["HANDLED_BY", "EXTENDS"]
308
+ query_groups.append(
309
+ QueryGroup(
310
+ purpose=QueryPurpose.CALLERS,
311
+ queries=primary_queries[:5],
312
+ weight=0.95,
313
+ required=True,
314
+ )
315
+ )
316
+ query_groups.append(
317
+ QueryGroup(
318
+ purpose=QueryPurpose.DEPENDENCIES,
319
+ queries=primary_queries[:5],
320
+ weight=0.8,
321
+ required=True,
322
+ )
323
+ )
324
+ query_groups.append(
325
+ QueryGroup(
326
+ purpose=QueryPurpose.TESTS,
327
+ queries=primary_queries[:3],
328
+ weight=0.75,
329
+ required=True,
330
+ )
331
+ )
332
+
333
+ elif intent == TaskIntent.REVIEW.value:
334
+ include_git = True
335
+ entry_point_strategy = "GIT_DIFF_ENTRY"
336
+ max_depth = 2
337
+ required_relationships = ["CALLS"]
338
+ optional_relationships = ["IMPORTS"]
339
+ query_groups.append(
340
+ QueryGroup(
341
+ purpose=QueryPurpose.GIT,
342
+ queries=primary_queries or ("HEAD~1..HEAD",),
343
+ weight=1.0,
344
+ required=True,
345
+ )
346
+ )
347
+ query_groups.append(
348
+ QueryGroup(
349
+ purpose=QueryPurpose.TESTS,
350
+ queries=primary_queries[:3],
351
+ weight=0.8,
352
+ required=True,
353
+ )
354
+ )
355
+
356
+ elif intent == TaskIntent.ARCHITECTURE.value:
357
+ include_architecture = True
358
+ include_tests = False
359
+ max_depth = 2
360
+ required_relationships = ["HANDLED_BY", "IMPORTS"]
361
+ optional_relationships = ["CALLS", "EXTENDS"]
362
+ query_groups.append(
363
+ QueryGroup(
364
+ purpose=QueryPurpose.ARCHITECTURE,
365
+ queries=primary_queries,
366
+ weight=1.0,
367
+ required=True,
368
+ )
369
+ )
370
+ query_groups.append(
371
+ QueryGroup(
372
+ purpose=QueryPurpose.FRAMEWORK,
373
+ queries=primary_queries,
374
+ weight=0.85,
375
+ required=False,
376
+ )
377
+ )
378
+
379
+ elif intent == TaskIntent.TEST.value:
380
+ include_tests = True
381
+ max_depth = 2
382
+ required_relationships = ["TESTED_BY", "CALLS"]
383
+ optional_relationships = ["IMPORTS"]
384
+ query_groups.append(
385
+ QueryGroup(
386
+ purpose=QueryPurpose.TESTS,
387
+ queries=primary_queries,
388
+ weight=1.0,
389
+ required=True,
390
+ )
391
+ )
392
+
393
+ # Ambiguity policy handling
394
+ has_ambiguity = any(a.status == AmbiguityStatus.AMBIGUOUS for a in ambiguities)
395
+ ambiguity_policy = "REPORT_OR_ASSUME" if has_ambiguity else "CLEAR"
396
+
397
+ return RetrievalPlan(
398
+ schema_version=PLAN_SCHEMA_VERSION,
399
+ task_spec_hash=spec_hash,
400
+ task_fingerprint=spec_hash,
401
+ intent=intent,
402
+ query_groups=tuple(query_groups),
403
+ required_relationships=tuple(dict.fromkeys(required_relationships)),
404
+ optional_relationships=tuple(dict.fromkeys(optional_relationships)),
405
+ include_tests=include_tests,
406
+ include_git=include_git,
407
+ include_framework=include_framework,
408
+ include_architecture=include_architecture,
409
+ entry_point_strategy=entry_point_strategy,
410
+ max_depth=max_depth,
411
+ max_nodes=max_nodes,
412
+ max_edges=max_edges,
413
+ token_budget=token_budget,
414
+ freshness_policy="REQUIRE_FRESH",
415
+ evidence_policy="VERIFY_SOURCE_HASH",
416
+ ambiguity_policy=ambiguity_policy,
417
+ )