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
@@ -0,0 +1,197 @@
1
+ """Branch Architecture Comparison Engine.
2
+
3
+ Provides hierarchical structural comparisons between Git branches:
4
+ package
5
+ ↓
6
+ module
7
+ ↓
8
+ symbol
9
+ ↓
10
+ relationships (routes, tests, DB writes, calls)
11
+
12
+ Supports:
13
+ - deterministic ordering
14
+ - token-budget awareness (max_tokens)
15
+ - cursor-based pagination
16
+ - explicit summary of changed routes, services, database models, and affected tests
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import sqlite3
21
+ from dataclasses import dataclass, field
22
+ from pathlib import Path
23
+ from typing import Any
24
+
25
+ from codegraph.monorepo import detect_workspace
26
+ from codegraph.structural_diff import compare_branches
27
+
28
+
29
+ @dataclass
30
+ class SymbolChangeItem:
31
+ name: str
32
+ kind: str
33
+ change_type: str # "ADDED" | "MODIFIED" | "REMOVED"
34
+ line: int | None
35
+ relationships: list[str] = field(default_factory=list)
36
+
37
+ def as_dict(self) -> dict[str, Any]:
38
+ return {
39
+ "name": self.name,
40
+ "kind": self.kind,
41
+ "change_type": self.change_type,
42
+ "line": self.line,
43
+ "relationships": self.relationships,
44
+ }
45
+
46
+
47
+ @dataclass
48
+ class ModuleChangeItem:
49
+ module: str
50
+ file_path: str
51
+ symbols: list[SymbolChangeItem] = field(default_factory=list)
52
+
53
+ def as_dict(self) -> dict[str, Any]:
54
+ return {
55
+ "module": self.module,
56
+ "file_path": self.file_path,
57
+ "symbols": [s.as_dict() for s in self.symbols],
58
+ }
59
+
60
+
61
+ @dataclass
62
+ class PackageChangeItem:
63
+ package_id: str
64
+ modules: list[ModuleChangeItem] = field(default_factory=list)
65
+
66
+ def as_dict(self) -> dict[str, Any]:
67
+ return {
68
+ "package_id": self.package_id,
69
+ "modules": [m.as_dict() for m in self.modules],
70
+ }
71
+
72
+
73
+ @dataclass
74
+ class BranchArchitectureReport:
75
+ base_branch: str
76
+ head_branch: str
77
+ packages: list[PackageChangeItem] = field(default_factory=list)
78
+ changed_routes: list[dict[str, str]] = field(default_factory=list)
79
+ changed_services: list[str] = field(default_factory=list)
80
+ changed_db: list[dict[str, str]] = field(default_factory=list)
81
+ affected_tests: list[str] = field(default_factory=list)
82
+ next_cursor: str | None = None
83
+ total_packages: int = 0
84
+ total_symbols: int = 0
85
+ estimated_tokens: int = 0
86
+
87
+ def as_dict(self) -> dict[str, Any]:
88
+ return {
89
+ "base_branch": self.base_branch,
90
+ "head_branch": self.head_branch,
91
+ "packages": [p.as_dict() for p in self.packages],
92
+ "changed_routes": self.changed_routes,
93
+ "changed_services": self.changed_services,
94
+ "changed_db": self.changed_db,
95
+ "affected_tests": self.affected_tests,
96
+ "next_cursor": self.next_cursor,
97
+ "total_packages": self.total_packages,
98
+ "total_symbols": self.total_symbols,
99
+ "estimated_tokens": self.estimated_tokens,
100
+ }
101
+
102
+
103
+ def compare_branch_architecture(
104
+ repository: Path,
105
+ base_branch: str = "main",
106
+ head_branch: str = "HEAD",
107
+ con: sqlite3.Connection | None = None,
108
+ limit: int = 50,
109
+ cursor: str | None = None,
110
+ max_tokens: int = 4000,
111
+ ) -> BranchArchitectureReport:
112
+ """Compare two branches and return hierarchical architecture diff."""
113
+ if base_branch == head_branch:
114
+ return BranchArchitectureReport(base_branch=base_branch, head_branch=head_branch)
115
+
116
+ # 1. Run structural branch diff
117
+ diff_report = compare_branches(repository, base_branch=base_branch, head_branch=head_branch, con=con)
118
+
119
+ # 2. Workspace package mapper
120
+ ws = detect_workspace(repository, con=con)
121
+
122
+ # 3. Build hierarchical package -> module -> symbol map
123
+ package_map: dict[str, dict[str, list[SymbolChangeItem]]] = {}
124
+ services: set[str] = set()
125
+
126
+ all_symbols = diff_report.added_symbols + diff_report.changed_symbols + diff_report.removed_symbols
127
+ # Sort deterministically by path and name
128
+ all_symbols.sort(key=lambda s: (s.path, s.name))
129
+
130
+ # Apply cursor pagination if cursor provided
131
+ start_idx = 0
132
+ if cursor and cursor.isdigit():
133
+ start_idx = int(cursor)
134
+
135
+ paged_symbols = all_symbols[start_idx : start_idx + limit]
136
+ next_cursor = str(start_idx + limit) if (start_idx + limit) < len(all_symbols) else None
137
+
138
+ for s in paged_symbols:
139
+ pkg = ws.get_package_for_file(s.path)
140
+ pkg_id = pkg.package_id if pkg else "root"
141
+
142
+ if pkg_id not in package_map:
143
+ package_map[pkg_id] = {}
144
+ if s.path not in package_map[pkg_id]:
145
+ package_map[pkg_id][s.path] = []
146
+
147
+ # Find associated relationships
148
+ rels: list[str] = []
149
+ for r in diff_report.changed_routes:
150
+ if r.handler == s.name:
151
+ rels.append(f"{r.change_type} ROUTE {r.method} {r.path}")
152
+ for db in diff_report.db_impact:
153
+ if db.get("symbol") == s.name:
154
+ rels.append(f"{db.get('change_type')} DB {db.get('operation')} {db.get('table')}")
155
+
156
+ if "service" in s.name.lower() or "service" in s.path.lower():
157
+ services.add(s.name)
158
+
159
+ package_map[pkg_id][s.path].append(
160
+ SymbolChangeItem(
161
+ name=s.name,
162
+ kind=s.kind,
163
+ change_type=s.change_type,
164
+ line=s.new_line or s.old_line,
165
+ relationships=rels,
166
+ )
167
+ )
168
+
169
+ # Build ordered PackageChangeItem objects
170
+ package_items: list[PackageChangeItem] = []
171
+ total_sym_count = 0
172
+
173
+ for pkg_id in sorted(package_map.keys()):
174
+ module_items: list[ModuleChangeItem] = []
175
+ for f_path in sorted(package_map[pkg_id].keys()):
176
+ mod_name = Path(f_path).stem
177
+ sym_items = package_map[pkg_id][f_path]
178
+ total_sym_count += len(sym_items)
179
+ module_items.append(ModuleChangeItem(module=mod_name, file_path=f_path, symbols=sym_items))
180
+ package_items.append(PackageChangeItem(package_id=pkg_id, modules=module_items))
181
+
182
+ # Rough token estimation: ~25 tokens per symbol + overhead
183
+ token_est = total_sym_count * 25 + len(diff_report.changed_routes) * 15 + 150
184
+
185
+ return BranchArchitectureReport(
186
+ base_branch=base_branch,
187
+ head_branch=head_branch,
188
+ packages=package_items,
189
+ changed_routes=[r.as_dict() for r in diff_report.changed_routes],
190
+ changed_services=sorted(services),
191
+ changed_db=diff_report.db_impact,
192
+ affected_tests=diff_report.affected_tests,
193
+ next_cursor=next_cursor,
194
+ total_packages=len(package_items),
195
+ total_symbols=total_sym_count,
196
+ estimated_tokens=token_est,
197
+ )
codegraph/cache.py ADDED
@@ -0,0 +1,95 @@
1
+ """Deterministic Task Fingerprinting and Context Caching Engine.
2
+
3
+ Guarantees repository generation consistency and cache invalidation on:
4
+ - Source code or index generation change
5
+ - Parser version change
6
+ - Database schema change
7
+ - Configuration change
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import hashlib
12
+ import json
13
+ import sqlite3
14
+ import time
15
+ from typing import Any, cast
16
+
17
+ from codegraph.indexing.parser import PARSER_VERSION
18
+ from codegraph.task import TaskSpec
19
+
20
+ CACHE_SCHEMA_VERSION = 1
21
+
22
+
23
+ def compute_context_cache_key(
24
+ task_spec: TaskSpec,
25
+ repository_generation: int,
26
+ max_tokens: int,
27
+ parser_version: str = PARSER_VERSION,
28
+ extra_config: str = "",
29
+ ) -> str:
30
+ """Compute an immutable, deterministic cache key for a context compilation request."""
31
+ canonical_components = {
32
+ "intent": task_spec.intent,
33
+ "goal": task_spec.goal,
34
+ "targets": sorted(task_spec.targets),
35
+ "operations": sorted(task_spec.operations),
36
+ "constraints": sorted(task_spec.constraints),
37
+ "exclusions": sorted(task_spec.exclusions),
38
+ "scope_paths": sorted(task_spec.scope_paths),
39
+ "time_scope": task_spec.time_scope or "",
40
+ "repository_generation": repository_generation,
41
+ "max_tokens": max_tokens,
42
+ "parser_version": parser_version,
43
+ "cache_schema": CACHE_SCHEMA_VERSION,
44
+ "extra_config": extra_config,
45
+ }
46
+ raw = json.dumps(canonical_components, sort_keys=True, separators=(",", ":")).encode("utf-8")
47
+ return f"ctx:{hashlib.sha256(raw).hexdigest()}"
48
+
49
+
50
+ def get_cached_context_packet(
51
+ con: sqlite3.Connection,
52
+ cache_key: str,
53
+ ) -> dict[str, Any] | None:
54
+ """Retrieve cached context packet if present in SQLite context_cache."""
55
+ try:
56
+ row = con.execute(
57
+ "SELECT data FROM context_cache WHERE cache_key=?",
58
+ (cache_key,),
59
+ ).fetchone()
60
+ if row:
61
+ raw_data = row["data"] if isinstance(row, sqlite3.Row) else row[0]
62
+ parsed = json.loads(raw_data)
63
+ if isinstance(parsed, dict):
64
+ return cast(dict[str, Any], parsed)
65
+ return None
66
+ except Exception:
67
+ pass
68
+ return None
69
+
70
+
71
+ def store_cached_context_packet(
72
+ con: sqlite3.Connection,
73
+ cache_key: str,
74
+ packet_dict: dict[str, Any],
75
+ ) -> None:
76
+ """Store compiled ContextPacket in SQLite context_cache table."""
77
+ try:
78
+ now = int(time.time())
79
+ serialized = json.dumps(packet_dict, sort_keys=True)
80
+ con.execute(
81
+ "INSERT OR REPLACE INTO context_cache (cache_key, data, created_at) VALUES (?, ?, ?)",
82
+ (cache_key, serialized, now),
83
+ )
84
+ con.commit()
85
+ except Exception:
86
+ pass
87
+
88
+
89
+ def invalidate_context_cache(con: sqlite3.Connection) -> None:
90
+ """Explicitly wipe context cache upon repository mutation or index generation advancement."""
91
+ try:
92
+ con.execute("DELETE FROM context_cache")
93
+ con.commit()
94
+ except Exception:
95
+ pass