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,337 @@
1
+ """Deterministic Next.js App Router and Server Actions analyzer.
2
+
3
+ Features:
4
+ - App Router directory-derived route mapping (`app/**/route.ts` and `app/**/page.tsx`).
5
+ - Route group unwrapping: `app/(auth)/login/route.ts` -> `/login`.
6
+ - Dynamic segment normalization: `[id]` -> `{id}`, `[...slug]` -> `{slug}`, `[[...slug]]` -> `{slug}`.
7
+ - HTTP method route handlers: `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS`.
8
+ - Page routes: default exports from `page.tsx` mapped to `GET` routes.
9
+ - Server Actions detection:
10
+ - File-level `'use server'` marks all exported async functions as `SERVER_ACTION`.
11
+ - Function-level `'use server'` marks specific functions as `SERVER_ACTION`.
12
+ - Client Component hydration boundary detection: file-level `'use client'`.
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import re
17
+ from dataclasses import dataclass, field
18
+
19
+ from codegraph.frameworks import FrameworkEvidence, RouteDetection, normalize_route_path
20
+ from codegraph.indexing.models import BindingRef
21
+
22
+ _NEXT_ROUTE_METHODS = frozenset({
23
+ "GET",
24
+ "POST",
25
+ "PUT",
26
+ "DELETE",
27
+ "PATCH",
28
+ "OPTIONS",
29
+ "HEAD",
30
+ })
31
+
32
+ # Matches export (async) function NAME
33
+ _EXPORT_FUNC_RE = re.compile(
34
+ r"\bexport\s+(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\s*\("
35
+ )
36
+
37
+ # Matches export const NAME = (async) (
38
+ _EXPORT_CONST_FUNC_RE = re.compile(
39
+ r"\bexport\s+const\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*=>"
40
+ )
41
+
42
+ # Matches export default function/const
43
+ _EXPORT_DEFAULT_RE = re.compile(
44
+ r"\bexport\s+default\s+(?:async\s+)?(?:function\s*([A-Za-z_$][\w$]*)?|class\s*([A-Za-z_$][\w$]*)?|([A-Za-z_$][\w$]*))"
45
+ )
46
+
47
+ # Function body scan for inline 'use server'
48
+ _INLINE_USE_SERVER_RE = re.compile(
49
+ r"(?:async\s+function\s+([A-Za-z_$][\w$]*)|(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*async)[\s\S]*?\{[\s\S]*?['\"`]use server['\"`]"
50
+ )
51
+
52
+
53
+ @dataclass
54
+ class NextjsAnalysisResult:
55
+ routes: list[RouteDetection] = field(default_factory=list)
56
+ evidence: list[FrameworkEvidence] = field(default_factory=list)
57
+ bindings: list[BindingRef] = field(default_factory=list)
58
+ server_actions: list[str] = field(default_factory=list)
59
+ is_client_component: bool = False
60
+ is_server_actions_file: bool = False
61
+
62
+
63
+ def resolve_nextjs_route_path(file_path: str) -> tuple[str, str]:
64
+ """Derive canonical URL route and normalized route from Next.js App Router file path.
65
+
66
+ Handles:
67
+ - Root and nested app dirs: `app/...` or `src/app/...`
68
+ - Route groups: `app/(dashboard)/invoices/page.tsx` -> `/invoices`
69
+ - Dynamic params: `[id]` -> `{id}`, `[...slug]` -> `{slug}`
70
+ """
71
+ norm_path = file_path.replace("\\", "/").strip("/")
72
+
73
+ # Find where app/ or pages/ starts
74
+ app_idx = -1
75
+ for prefix in ("/src/app/", "src/app/", "/app/", "app/"):
76
+ idx = norm_path.find(prefix)
77
+ if idx != -1:
78
+ app_idx = idx + len(prefix)
79
+ break
80
+
81
+ if app_idx == -1:
82
+ # Fallback: check if path contains route.ts/page.tsx directly
83
+ subpath = norm_path.rsplit("/", 1)[0] if "/" in norm_path else ""
84
+ else:
85
+ subpath = norm_path[app_idx:]
86
+ if "/" in subpath:
87
+ subpath = subpath.rsplit("/", 1)[0]
88
+ else:
89
+ subpath = ""
90
+
91
+ # Split into path segments and strip route groups (parenthesized folders) and parallel routes (@)
92
+ raw_segments = subpath.split("/") if subpath else []
93
+ cleaned_segments: list[str] = []
94
+ for seg in raw_segments:
95
+ s = seg.strip()
96
+ if not s:
97
+ continue
98
+ # Route groups like (auth), (dashboard) are omitted from route path
99
+ if s.startswith("(") and s.endswith(")"):
100
+ continue
101
+ # Parallel slots like @modal are omitted from route path
102
+ if s.startswith("@"):
103
+ continue
104
+ cleaned_segments.append(s)
105
+
106
+ raw_route = "/" + "/".join(cleaned_segments) if cleaned_segments else "/"
107
+ normalized = normalize_route_path(raw_route, "nextjs")
108
+ return raw_route, normalized
109
+
110
+
111
+ def analyze_nextjs_file(
112
+ content: str,
113
+ file_path: str,
114
+ module: str,
115
+ ) -> NextjsAnalysisResult:
116
+ """Analyze a TypeScript/JavaScript file for Next.js App Router routes, Server Actions, and Client Components."""
117
+ res = NextjsAnalysisResult()
118
+ if not content:
119
+ return res
120
+
121
+ norm_path = file_path.replace("\\", "/").lower()
122
+ is_route_file = (
123
+ norm_path.endswith("/route.ts")
124
+ or norm_path.endswith("/route.js")
125
+ or norm_path.endswith("/route.mjs")
126
+ or norm_path == "route.ts"
127
+ or norm_path == "route.js"
128
+ )
129
+ is_page_file = (
130
+ norm_path.endswith("/page.tsx")
131
+ or norm_path.endswith("/page.jsx")
132
+ or norm_path.endswith("/page.ts")
133
+ or norm_path.endswith("/page.js")
134
+ or norm_path == "page.tsx"
135
+ or norm_path == "page.jsx"
136
+ )
137
+
138
+ lines = content.splitlines()
139
+
140
+ # 1. Inspect top directives: 'use server' or 'use client'
141
+ top_use_server = False
142
+ for line_idx, line in enumerate(lines[:15], start=1):
143
+ stripped = line.strip()
144
+ if not stripped or stripped.startswith(("//", "/*", "*")):
145
+ continue
146
+ if stripped in ("'use server';", '"use server";', "'use server'", '"use server"'):
147
+ top_use_server = True
148
+ res.is_server_actions_file = True
149
+ res.evidence.append(
150
+ FrameworkEvidence(
151
+ framework="nextjs",
152
+ construct_type="SERVER_ACTION_FILE",
153
+ file_path=file_path,
154
+ line=line_idx,
155
+ column=line.find(stripped),
156
+ evidence="File-level 'use server' directive",
157
+ )
158
+ )
159
+ break
160
+ elif stripped in ("'use client';", '"use client";', "'use client'", '"use client"'):
161
+ res.is_client_component = True
162
+ res.evidence.append(
163
+ FrameworkEvidence(
164
+ framework="nextjs",
165
+ construct_type="CLIENT_COMPONENT",
166
+ file_path=file_path,
167
+ line=line_idx,
168
+ column=line.find(stripped),
169
+ evidence="Client component hydration boundary ('use client')",
170
+ )
171
+ )
172
+ break
173
+ # First non-comment statement that is not a directive terminates directive search
174
+ if not stripped.startswith(("import ", "'use ", '"use ')):
175
+ break
176
+
177
+ # 2. Server Actions:
178
+ # If file has file-level 'use server', any exported async function is a Server Action
179
+ if top_use_server:
180
+ for line_idx, line in enumerate(lines, start=1):
181
+ for m in _EXPORT_FUNC_RE.finditer(line):
182
+ fn_name = m.group(1)
183
+ res.server_actions.append(fn_name)
184
+ res.evidence.append(
185
+ FrameworkEvidence(
186
+ framework="nextjs",
187
+ construct_type="SERVER_ACTION",
188
+ file_path=file_path,
189
+ line=line_idx,
190
+ column=m.start(),
191
+ evidence=f"Next.js Server Action: export async function {fn_name}",
192
+ )
193
+ )
194
+ res.bindings.append(
195
+ BindingRef(
196
+ target_name=f"{module}.{fn_name}",
197
+ source_expr=fn_name,
198
+ file_path=file_path,
199
+ line=line_idx,
200
+ scope="",
201
+ expr_kind="SERVER_ACTION",
202
+ base_expr="nextjs_server_action",
203
+ attr_name=fn_name,
204
+ )
205
+ )
206
+ for m in _EXPORT_CONST_FUNC_RE.finditer(line):
207
+ fn_name = m.group(1)
208
+ res.server_actions.append(fn_name)
209
+ res.evidence.append(
210
+ FrameworkEvidence(
211
+ framework="nextjs",
212
+ construct_type="SERVER_ACTION",
213
+ file_path=file_path,
214
+ line=line_idx,
215
+ column=m.start(),
216
+ evidence=f"Next.js Server Action: export const {fn_name} = async ...",
217
+ )
218
+ )
219
+ res.bindings.append(
220
+ BindingRef(
221
+ target_name=f"{module}.{fn_name}",
222
+ source_expr=fn_name,
223
+ file_path=file_path,
224
+ line=line_idx,
225
+ scope="",
226
+ expr_kind="SERVER_ACTION",
227
+ base_expr="nextjs_server_action",
228
+ attr_name=fn_name,
229
+ )
230
+ )
231
+ else:
232
+ # Check for inline 'use server' inside function bodies
233
+ for m in _INLINE_USE_SERVER_RE.finditer(content):
234
+ fn_name = m.group(1) or m.group(2)
235
+ if fn_name:
236
+ line_no = content[: m.start()].count("\n") + 1
237
+ res.server_actions.append(fn_name)
238
+ res.evidence.append(
239
+ FrameworkEvidence(
240
+ framework="nextjs",
241
+ construct_type="SERVER_ACTION",
242
+ file_path=file_path,
243
+ line=line_no,
244
+ column=None,
245
+ evidence=f"Next.js inline Server Action {fn_name}",
246
+ )
247
+ )
248
+ res.bindings.append(
249
+ BindingRef(
250
+ target_name=f"{module}.{fn_name}",
251
+ source_expr=fn_name,
252
+ file_path=file_path,
253
+ line=line_no,
254
+ scope="",
255
+ expr_kind="SERVER_ACTION",
256
+ base_expr="nextjs_server_action",
257
+ attr_name=fn_name,
258
+ )
259
+ )
260
+
261
+ # 3. Route Handlers: app/**/route.ts
262
+ if is_route_file:
263
+ raw_route, norm_route = resolve_nextjs_route_path(file_path)
264
+ for line_idx, line in enumerate(lines, start=1):
265
+ # Check function exports
266
+ for m in _EXPORT_FUNC_RE.finditer(line):
267
+ method_name = m.group(1).upper()
268
+ if method_name in _NEXT_ROUTE_METHODS:
269
+ res.routes.append(
270
+ RouteDetection(
271
+ framework="nextjs",
272
+ http_method=method_name,
273
+ route_path=raw_route,
274
+ normalized_route=norm_route,
275
+ handler_name=method_name,
276
+ handler_canonical_id=f"{module}.{method_name}",
277
+ file_path=file_path,
278
+ line=line_idx,
279
+ column=m.start(),
280
+ confidence="HIGH",
281
+ resolution_status="RESOLVED",
282
+ evidence=f"Next.js App Router HTTP handler {method_name} in {file_path}",
283
+ module=module,
284
+ router_name="export",
285
+ )
286
+ )
287
+ # Check const exports
288
+ for m in _EXPORT_CONST_FUNC_RE.finditer(line):
289
+ method_name = m.group(1).upper()
290
+ if method_name in _NEXT_ROUTE_METHODS:
291
+ res.routes.append(
292
+ RouteDetection(
293
+ framework="nextjs",
294
+ http_method=method_name,
295
+ route_path=raw_route,
296
+ normalized_route=norm_route,
297
+ handler_name=method_name,
298
+ handler_canonical_id=f"{module}.{method_name}",
299
+ file_path=file_path,
300
+ line=line_idx,
301
+ column=m.start(),
302
+ confidence="HIGH",
303
+ resolution_status="RESOLVED",
304
+ evidence=f"Next.js App Router HTTP handler {method_name} in {file_path}",
305
+ module=module,
306
+ router_name="export",
307
+ )
308
+ )
309
+
310
+ # 4. Page Routes: app/**/page.tsx
311
+ elif is_page_file:
312
+ raw_route, norm_route = resolve_nextjs_route_path(file_path)
313
+ for line_idx, line in enumerate(lines, start=1):
314
+ page_m = _EXPORT_DEFAULT_RE.search(line)
315
+ if page_m:
316
+ fn_name = page_m.group(1) or page_m.group(2) or page_m.group(3) or "default"
317
+ res.routes.append(
318
+ RouteDetection(
319
+ framework="nextjs",
320
+ http_method="GET",
321
+ route_path=raw_route,
322
+ normalized_route=norm_route,
323
+ handler_name=fn_name,
324
+ handler_canonical_id=f"{module}.{fn_name}",
325
+ file_path=file_path,
326
+ line=line_idx,
327
+ column=page_m.start(),
328
+ confidence="HIGH",
329
+ resolution_status="RESOLVED",
330
+ evidence=f"Next.js App Router Page route GET {raw_route} ({fn_name})",
331
+ module=module,
332
+ router_name="page",
333
+ )
334
+ )
335
+ break
336
+
337
+ return res