codeframe-ai 0.9.0__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 (197) hide show
  1. codeframe/__init__.py +11 -0
  2. codeframe/__main__.py +20 -0
  3. codeframe/adapters/__init__.py +5 -0
  4. codeframe/adapters/e2b/__init__.py +13 -0
  5. codeframe/adapters/e2b/adapter.py +342 -0
  6. codeframe/adapters/e2b/budget.py +71 -0
  7. codeframe/adapters/e2b/credential_scanner.py +134 -0
  8. codeframe/adapters/llm/__init__.py +92 -0
  9. codeframe/adapters/llm/anthropic.py +414 -0
  10. codeframe/adapters/llm/base.py +444 -0
  11. codeframe/adapters/llm/mock.py +281 -0
  12. codeframe/adapters/llm/openai.py +483 -0
  13. codeframe/agents/__init__.py +8 -0
  14. codeframe/agents/dependency_resolver.py +714 -0
  15. codeframe/auth/__init__.py +16 -0
  16. codeframe/auth/api_key_router.py +238 -0
  17. codeframe/auth/api_keys.py +156 -0
  18. codeframe/auth/dependencies.py +358 -0
  19. codeframe/auth/manager.py +178 -0
  20. codeframe/auth/models.py +30 -0
  21. codeframe/auth/router.py +93 -0
  22. codeframe/auth/schemas.py +15 -0
  23. codeframe/auth/scopes.py +53 -0
  24. codeframe/cli/__init__.py +12 -0
  25. codeframe/cli/__main__.py +20 -0
  26. codeframe/cli/api_client.py +275 -0
  27. codeframe/cli/app.py +5688 -0
  28. codeframe/cli/auth.py +122 -0
  29. codeframe/cli/auth_commands.py +958 -0
  30. codeframe/cli/commands/__init__.py +5 -0
  31. codeframe/cli/config_commands.py +79 -0
  32. codeframe/cli/dashboard_commands.py +67 -0
  33. codeframe/cli/engines_commands.py +205 -0
  34. codeframe/cli/env_commands.py +409 -0
  35. codeframe/cli/helpers.py +56 -0
  36. codeframe/cli/hooks_commands.py +208 -0
  37. codeframe/cli/import_commands.py +129 -0
  38. codeframe/cli/pr_commands.py +549 -0
  39. codeframe/cli/proof_commands.py +415 -0
  40. codeframe/cli/stats_commands.py +311 -0
  41. codeframe/cli/telemetry_runtime.py +153 -0
  42. codeframe/cli/validators.py +123 -0
  43. codeframe/config/rate_limits.py +165 -0
  44. codeframe/core/__init__.py +15 -0
  45. codeframe/core/adapters/__init__.py +43 -0
  46. codeframe/core/adapters/agent_adapter.py +114 -0
  47. codeframe/core/adapters/builtin.py +326 -0
  48. codeframe/core/adapters/claude_code.py +62 -0
  49. codeframe/core/adapters/codex.py +393 -0
  50. codeframe/core/adapters/git_utils.py +40 -0
  51. codeframe/core/adapters/kilocode.py +126 -0
  52. codeframe/core/adapters/opencode.py +48 -0
  53. codeframe/core/adapters/streaming_chat.py +483 -0
  54. codeframe/core/adapters/subprocess_adapter.py +213 -0
  55. codeframe/core/adapters/verification_wrapper.py +269 -0
  56. codeframe/core/agent.py +2183 -0
  57. codeframe/core/agents_config.py +569 -0
  58. codeframe/core/api_key_service.py +211 -0
  59. codeframe/core/artifacts.py +428 -0
  60. codeframe/core/blocker_detection.py +218 -0
  61. codeframe/core/blockers.py +433 -0
  62. codeframe/core/checkpoints.py +481 -0
  63. codeframe/core/conductor.py +2255 -0
  64. codeframe/core/config.py +827 -0
  65. codeframe/core/config_watcher.py +268 -0
  66. codeframe/core/context.py +542 -0
  67. codeframe/core/context_packager.py +234 -0
  68. codeframe/core/credentials.py +735 -0
  69. codeframe/core/dependency_analyzer.py +229 -0
  70. codeframe/core/dependency_graph.py +290 -0
  71. codeframe/core/diagnostic_agent.py +712 -0
  72. codeframe/core/diagnostics.py +616 -0
  73. codeframe/core/editor.py +556 -0
  74. codeframe/core/engine_registry.py +256 -0
  75. codeframe/core/engine_stats.py +231 -0
  76. codeframe/core/environment.py +697 -0
  77. codeframe/core/events.py +375 -0
  78. codeframe/core/executor.py +1005 -0
  79. codeframe/core/fix_tracker.py +480 -0
  80. codeframe/core/gates.py +1322 -0
  81. codeframe/core/git.py +477 -0
  82. codeframe/core/github_connect_service.py +178 -0
  83. codeframe/core/github_integration_config.py +118 -0
  84. codeframe/core/github_issues_service.py +449 -0
  85. codeframe/core/hooks.py +184 -0
  86. codeframe/core/importers/__init__.py +1 -0
  87. codeframe/core/importers/ralph.py +540 -0
  88. codeframe/core/installer.py +650 -0
  89. codeframe/core/models.py +1026 -0
  90. codeframe/core/notifications_config.py +183 -0
  91. codeframe/core/planner.py +437 -0
  92. codeframe/core/prd.py +670 -0
  93. codeframe/core/prd_discovery.py +1118 -0
  94. codeframe/core/prd_stress_test.py +499 -0
  95. codeframe/core/progress.py +126 -0
  96. codeframe/core/proof/__init__.py +34 -0
  97. codeframe/core/proof/capture.py +79 -0
  98. codeframe/core/proof/evidence.py +56 -0
  99. codeframe/core/proof/ledger.py +574 -0
  100. codeframe/core/proof/models.py +162 -0
  101. codeframe/core/proof/obligations.py +103 -0
  102. codeframe/core/proof/runner.py +233 -0
  103. codeframe/core/proof/scope.py +81 -0
  104. codeframe/core/proof/stubs.py +156 -0
  105. codeframe/core/quick_fixes.py +558 -0
  106. codeframe/core/react_agent.py +1650 -0
  107. codeframe/core/reconciliation.py +183 -0
  108. codeframe/core/replay.py +788 -0
  109. codeframe/core/review.py +285 -0
  110. codeframe/core/runtime.py +1134 -0
  111. codeframe/core/sandbox/__init__.py +27 -0
  112. codeframe/core/sandbox/context.py +98 -0
  113. codeframe/core/sandbox/worktree.py +20 -0
  114. codeframe/core/schedule.py +396 -0
  115. codeframe/core/stall_detector.py +71 -0
  116. codeframe/core/stall_monitor.py +134 -0
  117. codeframe/core/state_machine.py +121 -0
  118. codeframe/core/streaming.py +502 -0
  119. codeframe/core/task_tree.py +400 -0
  120. codeframe/core/tasks.py +1022 -0
  121. codeframe/core/telemetry.py +232 -0
  122. codeframe/core/templates.py +221 -0
  123. codeframe/core/tools.py +942 -0
  124. codeframe/core/workspace.py +887 -0
  125. codeframe/core/worktrees.py +276 -0
  126. codeframe/git/__init__.py +5 -0
  127. codeframe/git/github_integration.py +505 -0
  128. codeframe/lib/__init__.py +0 -0
  129. codeframe/lib/audit_logger.py +248 -0
  130. codeframe/lib/metrics_tracker.py +800 -0
  131. codeframe/lib/quality/__init__.py +7 -0
  132. codeframe/lib/quality/complexity_analyzer.py +316 -0
  133. codeframe/lib/quality/owasp_patterns.py +284 -0
  134. codeframe/lib/quality/security_scanner.py +250 -0
  135. codeframe/lib/rate_limiter.py +312 -0
  136. codeframe/notifications/__init__.py +0 -0
  137. codeframe/notifications/webhook.py +380 -0
  138. codeframe/planning/__init__.py +30 -0
  139. codeframe/planning/issue_generator.py +219 -0
  140. codeframe/planning/prd_template_functions.py +137 -0
  141. codeframe/planning/prd_templates.py +975 -0
  142. codeframe/planning/task_scheduler.py +511 -0
  143. codeframe/planning/task_templates.py +533 -0
  144. codeframe/platform_store/__init__.py +5 -0
  145. codeframe/platform_store/database.py +277 -0
  146. codeframe/platform_store/repositories/__init__.py +24 -0
  147. codeframe/platform_store/repositories/api_key_repository.py +245 -0
  148. codeframe/platform_store/repositories/audit_repository.py +67 -0
  149. codeframe/platform_store/repositories/base.py +295 -0
  150. codeframe/platform_store/repositories/interactive_sessions.py +165 -0
  151. codeframe/platform_store/repositories/token_repository.py +598 -0
  152. codeframe/platform_store/repositories/workspace_registry_repository.py +175 -0
  153. codeframe/platform_store/schema_manager.py +321 -0
  154. codeframe/templates/AGENTS.md.default +94 -0
  155. codeframe/tui/__init__.py +5 -0
  156. codeframe/tui/app.py +256 -0
  157. codeframe/tui/data_service.py +103 -0
  158. codeframe/ui/__init__.py +0 -0
  159. codeframe/ui/dependencies.py +103 -0
  160. codeframe/ui/models.py +999 -0
  161. codeframe/ui/response_models.py +201 -0
  162. codeframe/ui/routers/__init__.py +5 -0
  163. codeframe/ui/routers/_helpers.py +29 -0
  164. codeframe/ui/routers/batches_v2.py +315 -0
  165. codeframe/ui/routers/blockers_v2.py +320 -0
  166. codeframe/ui/routers/checkpoints_v2.py +310 -0
  167. codeframe/ui/routers/costs_v2.py +322 -0
  168. codeframe/ui/routers/diagnose_v2.py +225 -0
  169. codeframe/ui/routers/discovery_v2.py +417 -0
  170. codeframe/ui/routers/environment_v2.py +284 -0
  171. codeframe/ui/routers/events_v2.py +75 -0
  172. codeframe/ui/routers/gates_v2.py +166 -0
  173. codeframe/ui/routers/git_v2.py +284 -0
  174. codeframe/ui/routers/github_integrations_v2.py +532 -0
  175. codeframe/ui/routers/interactive_sessions_v2.py +238 -0
  176. codeframe/ui/routers/pr_v2.py +709 -0
  177. codeframe/ui/routers/prd_v2.py +695 -0
  178. codeframe/ui/routers/proof_v2.py +755 -0
  179. codeframe/ui/routers/review_v2.py +360 -0
  180. codeframe/ui/routers/schedule_v2.py +214 -0
  181. codeframe/ui/routers/session_chat_ws.py +354 -0
  182. codeframe/ui/routers/settings_v2.py +562 -0
  183. codeframe/ui/routers/streaming_v2.py +155 -0
  184. codeframe/ui/routers/tasks_v2.py +1098 -0
  185. codeframe/ui/routers/templates_v2.py +232 -0
  186. codeframe/ui/routers/terminal_ws.py +267 -0
  187. codeframe/ui/routers/workspace_v2.py +527 -0
  188. codeframe/ui/server.py +568 -0
  189. codeframe/ui/shared.py +241 -0
  190. codeframe/workspace/__init__.py +5 -0
  191. codeframe/workspace/manager.py +249 -0
  192. codeframe_ai-0.9.0.dist-info/METADATA +517 -0
  193. codeframe_ai-0.9.0.dist-info/RECORD +197 -0
  194. codeframe_ai-0.9.0.dist-info/WHEEL +5 -0
  195. codeframe_ai-0.9.0.dist-info/entry_points.txt +3 -0
  196. codeframe_ai-0.9.0.dist-info/licenses/LICENSE +661 -0
  197. codeframe_ai-0.9.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,285 @@
1
+ """Code review operations for CodeFRAME v2.
2
+
3
+ This module provides v2-compatible code review operations that work with
4
+ the Workspace model. It provides a simplified interface to the quality
5
+ analyzers without requiring v1 database persistence.
6
+
7
+ This module is headless - no FastAPI or HTTP dependencies.
8
+ """
9
+
10
+ import logging
11
+ from dataclasses import dataclass
12
+ from typing import Literal, Optional
13
+
14
+ from codeframe.core.workspace import Workspace
15
+ from codeframe.lib.quality.complexity_analyzer import ComplexityAnalyzer
16
+ from codeframe.lib.quality.security_scanner import SecurityScanner
17
+ from codeframe.lib.quality.owasp_patterns import OWASPPatterns
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ # ============================================================================
23
+ # Data Classes
24
+ # ============================================================================
25
+
26
+
27
+ @dataclass
28
+ class ReviewFinding:
29
+ """Individual review finding."""
30
+
31
+ category: str # complexity, security, style
32
+ severity: Literal["critical", "high", "medium", "low", "info"]
33
+ message: str
34
+ file_path: str
35
+ line_number: Optional[int] = None
36
+ suggestion: Optional[str] = None
37
+
38
+
39
+ @dataclass
40
+ class ReviewResult:
41
+ """Result of a code review."""
42
+
43
+ status: Literal["approved", "changes_requested", "rejected"]
44
+ overall_score: float
45
+ findings: list[ReviewFinding]
46
+ summary: str
47
+
48
+
49
+ @dataclass
50
+ class ReviewStatus:
51
+ """Review status for a task."""
52
+
53
+ has_review: bool
54
+ status: Optional[str]
55
+ overall_score: Optional[float]
56
+ findings_count: int
57
+
58
+
59
+ # ============================================================================
60
+ # Score Thresholds
61
+ # ============================================================================
62
+
63
+ EXCELLENT_THRESHOLD = 90
64
+ GOOD_THRESHOLD = 70
65
+ ACCEPTABLE_THRESHOLD = 50
66
+
67
+
68
+ # ============================================================================
69
+ # Review Functions
70
+ # ============================================================================
71
+
72
+
73
+ def _determine_status(score: float) -> Literal["approved", "changes_requested", "rejected"]:
74
+ """Determine review status based on score.
75
+
76
+ Args:
77
+ score: Overall review score (0-100)
78
+
79
+ Returns:
80
+ Review status
81
+ """
82
+ if score >= GOOD_THRESHOLD:
83
+ return "approved"
84
+ elif score >= ACCEPTABLE_THRESHOLD:
85
+ return "changes_requested"
86
+ else:
87
+ return "rejected"
88
+
89
+
90
+ def _severity_from_score(score: float) -> Literal["critical", "high", "medium", "low", "info"]:
91
+ """Determine severity based on score.
92
+
93
+ Args:
94
+ score: Individual finding score
95
+
96
+ Returns:
97
+ Severity level
98
+ """
99
+ if score < 30:
100
+ return "critical"
101
+ elif score < 50:
102
+ return "high"
103
+ elif score < 70:
104
+ return "medium"
105
+ elif score < 90:
106
+ return "low"
107
+ else:
108
+ return "info"
109
+
110
+
111
+ def review_files(
112
+ workspace: Workspace,
113
+ files: list[str],
114
+ ) -> ReviewResult:
115
+ """Run code review on specified files.
116
+
117
+ Performs complexity analysis, security scanning, and OWASP pattern
118
+ detection on the given files.
119
+
120
+ Args:
121
+ workspace: Target workspace
122
+ files: List of file paths to review (relative to repo root)
123
+
124
+ Returns:
125
+ ReviewResult with findings and overall score
126
+ """
127
+ project_path = workspace.repo_path
128
+ findings: list[ReviewFinding] = []
129
+
130
+ # Initialize analyzers
131
+ complexity_analyzer = ComplexityAnalyzer(project_path)
132
+ security_scanner = SecurityScanner(project_path)
133
+ owasp_checker = OWASPPatterns(project_path)
134
+
135
+ # Track scores for averaging
136
+ scores: list[float] = []
137
+
138
+ for file_path in files:
139
+ full_path = project_path / file_path
140
+
141
+ if not full_path.exists():
142
+ logger.warning(f"File not found: {file_path}")
143
+ continue
144
+
145
+ if not full_path.suffix == ".py":
146
+ # Only analyze Python files for now
147
+ continue
148
+
149
+ # Complexity analysis
150
+ try:
151
+ complexity_findings = complexity_analyzer.analyze_file(full_path)
152
+ for finding in complexity_findings:
153
+ findings.append(
154
+ ReviewFinding(
155
+ category=finding.category,
156
+ severity=finding.severity,
157
+ message=finding.message,
158
+ file_path=file_path,
159
+ line_number=finding.line_number,
160
+ suggestion=finding.suggestion,
161
+ )
162
+ )
163
+ # Map severity to score for averaging
164
+ severity_scores = {"critical": 20, "high": 40, "medium": 60, "low": 80, "info": 95}
165
+ scores.append(severity_scores.get(finding.severity, 60))
166
+ except Exception as e:
167
+ logger.warning(f"Complexity analysis failed for {file_path}: {e}")
168
+
169
+ # Security scan
170
+ try:
171
+ security_findings = security_scanner.analyze_file(full_path)
172
+ for finding in security_findings:
173
+ findings.append(
174
+ ReviewFinding(
175
+ category=finding.category,
176
+ severity=finding.severity,
177
+ message=finding.message,
178
+ file_path=file_path,
179
+ line_number=finding.line_number,
180
+ suggestion=finding.suggestion,
181
+ )
182
+ )
183
+ # Security issues have heavier weight on score
184
+ severity_scores = {"critical": 20, "high": 40, "medium": 60, "low": 80, "info": 95}
185
+ scores.append(severity_scores.get(finding.severity, 60))
186
+ except Exception as e:
187
+ logger.warning(f"Security scan failed for {file_path}: {e}")
188
+
189
+ # OWASP pattern check
190
+ try:
191
+ owasp_findings = owasp_checker.check_file(full_path)
192
+ for finding in owasp_findings:
193
+ findings.append(
194
+ ReviewFinding(
195
+ category=finding.category,
196
+ severity=finding.severity,
197
+ message=finding.message,
198
+ file_path=file_path,
199
+ line_number=finding.line_number,
200
+ suggestion=finding.suggestion,
201
+ )
202
+ )
203
+ # OWASP findings are typically high severity
204
+ severity_scores = {"critical": 20, "high": 40, "medium": 60, "low": 80, "info": 95}
205
+ scores.append(severity_scores.get(finding.severity, 40))
206
+ except Exception as e:
207
+ logger.warning(f"OWASP check failed for {file_path}: {e}")
208
+
209
+ # Calculate overall score
210
+ if scores:
211
+ overall_score = sum(scores) / len(scores)
212
+ else:
213
+ # No issues found = perfect score
214
+ overall_score = 100.0
215
+
216
+ status = _determine_status(overall_score)
217
+
218
+ # Generate summary
219
+ if not findings:
220
+ summary = "No issues found. Code looks good!"
221
+ else:
222
+ critical_count = sum(1 for f in findings if f.severity == "critical")
223
+ high_count = sum(1 for f in findings if f.severity == "high")
224
+ summary = f"Found {len(findings)} issues: {critical_count} critical, {high_count} high severity"
225
+
226
+ logger.info(f"Review completed: {status} (score: {overall_score:.1f})")
227
+
228
+ return ReviewResult(
229
+ status=status,
230
+ overall_score=round(overall_score, 1),
231
+ findings=findings,
232
+ summary=summary,
233
+ )
234
+
235
+
236
+ def review_task(
237
+ workspace: Workspace,
238
+ task_id: str,
239
+ files_modified: list[str],
240
+ ) -> ReviewResult:
241
+ """Run code review for a task's modified files.
242
+
243
+ Convenience function that wraps review_files with task context.
244
+
245
+ Args:
246
+ workspace: Target workspace
247
+ task_id: Task ID (for logging)
248
+ files_modified: List of modified file paths
249
+
250
+ Returns:
251
+ ReviewResult with findings and overall score
252
+ """
253
+ logger.info(f"Starting review for task {task_id} ({len(files_modified)} files)")
254
+ return review_files(workspace, files_modified)
255
+
256
+
257
+ def get_review_summary(result: ReviewResult) -> dict:
258
+ """Get a summary dict from review result.
259
+
260
+ Args:
261
+ result: ReviewResult from review_files/review_task
262
+
263
+ Returns:
264
+ Summary dict suitable for API responses
265
+ """
266
+ severity_counts = {
267
+ "critical": 0,
268
+ "high": 0,
269
+ "medium": 0,
270
+ "low": 0,
271
+ "info": 0,
272
+ }
273
+
274
+ for finding in result.findings:
275
+ if finding.severity in severity_counts:
276
+ severity_counts[finding.severity] += 1
277
+
278
+ return {
279
+ "status": result.status,
280
+ "overall_score": result.overall_score,
281
+ "total_findings": len(result.findings),
282
+ "severity_counts": severity_counts,
283
+ "summary": result.summary,
284
+ "has_blocking_issues": severity_counts["critical"] + severity_counts["high"] > 0,
285
+ }