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,238 @@
1
+ """V2 Interactive Sessions router.
2
+
3
+ Provides CRUD endpoints for persistent interactive agent sessions.
4
+
5
+ Routes:
6
+ POST /api/v2/sessions - Create session
7
+ GET /api/v2/sessions - List sessions (?workspace_path=&state=)
8
+ GET /api/v2/sessions/{id} - Get session
9
+ DELETE /api/v2/sessions/{id} - End/close session
10
+ POST /api/v2/sessions/{id}/messages - Add message to session
11
+ GET /api/v2/sessions/{id}/messages - Get message history (?limit=&offset=)
12
+
13
+ Auth note: auth is a project-wide gap tracked in #336. All other v2 routers also
14
+ lack auth — adding it only here would be inconsistent with the rest of the API.
15
+ """
16
+
17
+ import logging
18
+ from typing import Optional
19
+
20
+ from fastapi import APIRouter, HTTPException, Query, Request
21
+ from pydantic import BaseModel, field_validator
22
+
23
+ from codeframe.lib.rate_limiter import rate_limit_standard
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+ router = APIRouter(prefix="/api/v2/sessions", tags=["sessions-v2"])
28
+
29
+ VALID_STATES = frozenset({"active", "paused", "ended"})
30
+ VALID_ROLES = frozenset(
31
+ {"user", "assistant", "tool_use", "tool_result", "thinking", "system", "error"}
32
+ )
33
+
34
+
35
+ # ============================================================================
36
+ # Pydantic Schemas
37
+ # ============================================================================
38
+
39
+
40
+ class SessionCreate(BaseModel):
41
+ """Request body for creating a new interactive agent session."""
42
+
43
+ workspace_path: str
44
+ task_id: Optional[str] = None
45
+ # agent_type is intentionally open-ended for extensibility (claude, codex, opencode, etc.)
46
+ agent_type: str = "claude"
47
+ model: Optional[str] = None
48
+
49
+
50
+ class SessionResponse(BaseModel):
51
+ """Response body for a single interactive agent session."""
52
+
53
+ id: str
54
+ workspace_path: str
55
+ task_id: Optional[str]
56
+ state: str
57
+ agent_type: str
58
+ model: Optional[str]
59
+ cost_usd: float
60
+ input_tokens: int
61
+ output_tokens: int
62
+ created_at: str
63
+ updated_at: str
64
+ ended_at: Optional[str]
65
+
66
+
67
+ class MessageCreate(BaseModel):
68
+ """Request body for adding a message to a session."""
69
+
70
+ role: str
71
+ content: str
72
+ metadata: Optional[dict] = None
73
+
74
+ @field_validator("role")
75
+ @classmethod
76
+ def validate_role(cls, v: str) -> str:
77
+ """Validate that role is one of the allowed values."""
78
+ if v not in VALID_ROLES:
79
+ raise ValueError(f"role must be one of {sorted(VALID_ROLES)}")
80
+ return v
81
+
82
+
83
+ class MessageResponse(BaseModel):
84
+ """Response body for a single session message."""
85
+
86
+ id: str
87
+ session_id: str
88
+ role: str
89
+ content: str
90
+ metadata: Optional[dict]
91
+ created_at: str
92
+
93
+
94
+ # ============================================================================
95
+ # Helpers
96
+ # ============================================================================
97
+
98
+
99
+ def _get_repo(request: Request):
100
+ """Get the InteractiveSessionRepository from app state.
101
+
102
+ Raises 503 if app.state.db is not available (server lifespan should set it).
103
+ For backward compat with tests that set app.state.db directly.
104
+ """
105
+ db = getattr(request.app.state, "db", None)
106
+ if db is None:
107
+ raise HTTPException(
108
+ status_code=503,
109
+ detail="Database not available. Ensure the server is fully initialized.",
110
+ )
111
+ return db.interactive_sessions
112
+
113
+
114
+ def _session_to_response(row: dict) -> SessionResponse:
115
+ """Convert a DB row dict to a SessionResponse."""
116
+ return SessionResponse(
117
+ id=row["id"],
118
+ workspace_path=row["workspace_path"],
119
+ task_id=row.get("task_id"),
120
+ state=row["state"],
121
+ agent_type=row["agent_type"],
122
+ model=row.get("model"),
123
+ cost_usd=row.get("cost_usd", 0.0),
124
+ input_tokens=row.get("input_tokens", 0),
125
+ output_tokens=row.get("output_tokens", 0),
126
+ created_at=row["created_at"],
127
+ updated_at=row["updated_at"],
128
+ ended_at=row.get("ended_at"),
129
+ )
130
+
131
+
132
+ # ============================================================================
133
+ # Endpoints
134
+ # ============================================================================
135
+
136
+
137
+ @router.post("", status_code=201, response_model=SessionResponse)
138
+ @rate_limit_standard()
139
+ def create_session(body: SessionCreate, request: Request):
140
+ """Create a new interactive agent session."""
141
+ repo = _get_repo(request)
142
+ session = repo.create(
143
+ workspace_path=body.workspace_path,
144
+ task_id=body.task_id,
145
+ agent_type=body.agent_type,
146
+ model=body.model,
147
+ )
148
+ return _session_to_response(session)
149
+
150
+
151
+ @router.get("", response_model=list[SessionResponse])
152
+ @rate_limit_standard()
153
+ def list_sessions(
154
+ request: Request,
155
+ workspace_path: Optional[str] = Query(None),
156
+ state: Optional[str] = Query(None),
157
+ limit: int = Query(50, ge=1, le=200),
158
+ ):
159
+ """List sessions with optional filters by workspace_path and state."""
160
+ if state is not None and state not in VALID_STATES:
161
+ raise HTTPException(
162
+ status_code=422,
163
+ detail=f"Invalid state '{state}'. Must be one of {sorted(VALID_STATES)}",
164
+ )
165
+ repo = _get_repo(request)
166
+ sessions = repo.list(workspace_path=workspace_path, state=state, limit=limit)
167
+ return [_session_to_response(s) for s in sessions]
168
+
169
+
170
+ @router.get("/{session_id}", response_model=SessionResponse)
171
+ @rate_limit_standard()
172
+ def get_session(session_id: str, request: Request):
173
+ """Get a session by ID."""
174
+ repo = _get_repo(request)
175
+ session = repo.get(session_id)
176
+ if session is None:
177
+ raise HTTPException(status_code=404, detail="Session not found")
178
+ return _session_to_response(session)
179
+
180
+
181
+ @router.delete("/{session_id}", response_model=SessionResponse)
182
+ @rate_limit_standard()
183
+ def end_session(session_id: str, request: Request):
184
+ """End a session (sets state to 'ended' and records ended_at)."""
185
+ repo = _get_repo(request)
186
+ updated = repo.end(session_id)
187
+ if updated is None:
188
+ raise HTTPException(status_code=404, detail="Session not found")
189
+ return _session_to_response(updated)
190
+
191
+
192
+ @router.post("/{session_id}/messages", status_code=201, response_model=MessageResponse)
193
+ @rate_limit_standard()
194
+ def add_message(session_id: str, body: MessageCreate, request: Request):
195
+ """Add a message to a session's history."""
196
+ repo = _get_repo(request)
197
+ if repo.get(session_id) is None:
198
+ raise HTTPException(status_code=404, detail="Session not found")
199
+ message = repo.add_message(
200
+ session_id=session_id,
201
+ role=body.role,
202
+ content=body.content,
203
+ metadata=body.metadata,
204
+ )
205
+ return MessageResponse(
206
+ id=message["id"],
207
+ session_id=message["session_id"],
208
+ role=message["role"],
209
+ content=message["content"],
210
+ metadata=message.get("metadata"),
211
+ created_at=message["created_at"],
212
+ )
213
+
214
+
215
+ @router.get("/{session_id}/messages", response_model=list[MessageResponse])
216
+ @rate_limit_standard()
217
+ def get_messages(
218
+ session_id: str,
219
+ request: Request,
220
+ limit: int = Query(100, ge=1, le=500),
221
+ offset: int = Query(0, ge=0),
222
+ ):
223
+ """Get paginated message history for a session."""
224
+ repo = _get_repo(request)
225
+ if repo.get(session_id) is None:
226
+ raise HTTPException(status_code=404, detail="Session not found")
227
+ messages = repo.get_messages(session_id, limit=limit, offset=offset)
228
+ return [
229
+ MessageResponse(
230
+ id=m["id"],
231
+ session_id=m["session_id"],
232
+ role=m["role"],
233
+ content=m["content"],
234
+ metadata=m.get("metadata"),
235
+ created_at=m["created_at"],
236
+ )
237
+ for m in messages
238
+ ]