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.
- codeframe/__init__.py +11 -0
- codeframe/__main__.py +20 -0
- codeframe/adapters/__init__.py +5 -0
- codeframe/adapters/e2b/__init__.py +13 -0
- codeframe/adapters/e2b/adapter.py +342 -0
- codeframe/adapters/e2b/budget.py +71 -0
- codeframe/adapters/e2b/credential_scanner.py +134 -0
- codeframe/adapters/llm/__init__.py +92 -0
- codeframe/adapters/llm/anthropic.py +414 -0
- codeframe/adapters/llm/base.py +444 -0
- codeframe/adapters/llm/mock.py +281 -0
- codeframe/adapters/llm/openai.py +483 -0
- codeframe/agents/__init__.py +8 -0
- codeframe/agents/dependency_resolver.py +714 -0
- codeframe/auth/__init__.py +16 -0
- codeframe/auth/api_key_router.py +238 -0
- codeframe/auth/api_keys.py +156 -0
- codeframe/auth/dependencies.py +358 -0
- codeframe/auth/manager.py +178 -0
- codeframe/auth/models.py +30 -0
- codeframe/auth/router.py +93 -0
- codeframe/auth/schemas.py +15 -0
- codeframe/auth/scopes.py +53 -0
- codeframe/cli/__init__.py +12 -0
- codeframe/cli/__main__.py +20 -0
- codeframe/cli/api_client.py +275 -0
- codeframe/cli/app.py +5688 -0
- codeframe/cli/auth.py +122 -0
- codeframe/cli/auth_commands.py +958 -0
- codeframe/cli/commands/__init__.py +5 -0
- codeframe/cli/config_commands.py +79 -0
- codeframe/cli/dashboard_commands.py +67 -0
- codeframe/cli/engines_commands.py +205 -0
- codeframe/cli/env_commands.py +409 -0
- codeframe/cli/helpers.py +56 -0
- codeframe/cli/hooks_commands.py +208 -0
- codeframe/cli/import_commands.py +129 -0
- codeframe/cli/pr_commands.py +549 -0
- codeframe/cli/proof_commands.py +415 -0
- codeframe/cli/stats_commands.py +311 -0
- codeframe/cli/telemetry_runtime.py +153 -0
- codeframe/cli/validators.py +123 -0
- codeframe/config/rate_limits.py +165 -0
- codeframe/core/__init__.py +15 -0
- codeframe/core/adapters/__init__.py +43 -0
- codeframe/core/adapters/agent_adapter.py +114 -0
- codeframe/core/adapters/builtin.py +326 -0
- codeframe/core/adapters/claude_code.py +62 -0
- codeframe/core/adapters/codex.py +393 -0
- codeframe/core/adapters/git_utils.py +40 -0
- codeframe/core/adapters/kilocode.py +126 -0
- codeframe/core/adapters/opencode.py +48 -0
- codeframe/core/adapters/streaming_chat.py +483 -0
- codeframe/core/adapters/subprocess_adapter.py +213 -0
- codeframe/core/adapters/verification_wrapper.py +269 -0
- codeframe/core/agent.py +2183 -0
- codeframe/core/agents_config.py +569 -0
- codeframe/core/api_key_service.py +211 -0
- codeframe/core/artifacts.py +428 -0
- codeframe/core/blocker_detection.py +218 -0
- codeframe/core/blockers.py +433 -0
- codeframe/core/checkpoints.py +481 -0
- codeframe/core/conductor.py +2255 -0
- codeframe/core/config.py +827 -0
- codeframe/core/config_watcher.py +268 -0
- codeframe/core/context.py +542 -0
- codeframe/core/context_packager.py +234 -0
- codeframe/core/credentials.py +735 -0
- codeframe/core/dependency_analyzer.py +229 -0
- codeframe/core/dependency_graph.py +290 -0
- codeframe/core/diagnostic_agent.py +712 -0
- codeframe/core/diagnostics.py +616 -0
- codeframe/core/editor.py +556 -0
- codeframe/core/engine_registry.py +256 -0
- codeframe/core/engine_stats.py +231 -0
- codeframe/core/environment.py +697 -0
- codeframe/core/events.py +375 -0
- codeframe/core/executor.py +1005 -0
- codeframe/core/fix_tracker.py +480 -0
- codeframe/core/gates.py +1322 -0
- codeframe/core/git.py +477 -0
- codeframe/core/github_connect_service.py +178 -0
- codeframe/core/github_integration_config.py +118 -0
- codeframe/core/github_issues_service.py +449 -0
- codeframe/core/hooks.py +184 -0
- codeframe/core/importers/__init__.py +1 -0
- codeframe/core/importers/ralph.py +540 -0
- codeframe/core/installer.py +650 -0
- codeframe/core/models.py +1026 -0
- codeframe/core/notifications_config.py +183 -0
- codeframe/core/planner.py +437 -0
- codeframe/core/prd.py +670 -0
- codeframe/core/prd_discovery.py +1118 -0
- codeframe/core/prd_stress_test.py +499 -0
- codeframe/core/progress.py +126 -0
- codeframe/core/proof/__init__.py +34 -0
- codeframe/core/proof/capture.py +79 -0
- codeframe/core/proof/evidence.py +56 -0
- codeframe/core/proof/ledger.py +574 -0
- codeframe/core/proof/models.py +162 -0
- codeframe/core/proof/obligations.py +103 -0
- codeframe/core/proof/runner.py +233 -0
- codeframe/core/proof/scope.py +81 -0
- codeframe/core/proof/stubs.py +156 -0
- codeframe/core/quick_fixes.py +558 -0
- codeframe/core/react_agent.py +1650 -0
- codeframe/core/reconciliation.py +183 -0
- codeframe/core/replay.py +788 -0
- codeframe/core/review.py +285 -0
- codeframe/core/runtime.py +1134 -0
- codeframe/core/sandbox/__init__.py +27 -0
- codeframe/core/sandbox/context.py +98 -0
- codeframe/core/sandbox/worktree.py +20 -0
- codeframe/core/schedule.py +396 -0
- codeframe/core/stall_detector.py +71 -0
- codeframe/core/stall_monitor.py +134 -0
- codeframe/core/state_machine.py +121 -0
- codeframe/core/streaming.py +502 -0
- codeframe/core/task_tree.py +400 -0
- codeframe/core/tasks.py +1022 -0
- codeframe/core/telemetry.py +232 -0
- codeframe/core/templates.py +221 -0
- codeframe/core/tools.py +942 -0
- codeframe/core/workspace.py +887 -0
- codeframe/core/worktrees.py +276 -0
- codeframe/git/__init__.py +5 -0
- codeframe/git/github_integration.py +505 -0
- codeframe/lib/__init__.py +0 -0
- codeframe/lib/audit_logger.py +248 -0
- codeframe/lib/metrics_tracker.py +800 -0
- codeframe/lib/quality/__init__.py +7 -0
- codeframe/lib/quality/complexity_analyzer.py +316 -0
- codeframe/lib/quality/owasp_patterns.py +284 -0
- codeframe/lib/quality/security_scanner.py +250 -0
- codeframe/lib/rate_limiter.py +312 -0
- codeframe/notifications/__init__.py +0 -0
- codeframe/notifications/webhook.py +380 -0
- codeframe/planning/__init__.py +30 -0
- codeframe/planning/issue_generator.py +219 -0
- codeframe/planning/prd_template_functions.py +137 -0
- codeframe/planning/prd_templates.py +975 -0
- codeframe/planning/task_scheduler.py +511 -0
- codeframe/planning/task_templates.py +533 -0
- codeframe/platform_store/__init__.py +5 -0
- codeframe/platform_store/database.py +277 -0
- codeframe/platform_store/repositories/__init__.py +24 -0
- codeframe/platform_store/repositories/api_key_repository.py +245 -0
- codeframe/platform_store/repositories/audit_repository.py +67 -0
- codeframe/platform_store/repositories/base.py +295 -0
- codeframe/platform_store/repositories/interactive_sessions.py +165 -0
- codeframe/platform_store/repositories/token_repository.py +598 -0
- codeframe/platform_store/repositories/workspace_registry_repository.py +175 -0
- codeframe/platform_store/schema_manager.py +321 -0
- codeframe/templates/AGENTS.md.default +94 -0
- codeframe/tui/__init__.py +5 -0
- codeframe/tui/app.py +256 -0
- codeframe/tui/data_service.py +103 -0
- codeframe/ui/__init__.py +0 -0
- codeframe/ui/dependencies.py +103 -0
- codeframe/ui/models.py +999 -0
- codeframe/ui/response_models.py +201 -0
- codeframe/ui/routers/__init__.py +5 -0
- codeframe/ui/routers/_helpers.py +29 -0
- codeframe/ui/routers/batches_v2.py +315 -0
- codeframe/ui/routers/blockers_v2.py +320 -0
- codeframe/ui/routers/checkpoints_v2.py +310 -0
- codeframe/ui/routers/costs_v2.py +322 -0
- codeframe/ui/routers/diagnose_v2.py +225 -0
- codeframe/ui/routers/discovery_v2.py +417 -0
- codeframe/ui/routers/environment_v2.py +284 -0
- codeframe/ui/routers/events_v2.py +75 -0
- codeframe/ui/routers/gates_v2.py +166 -0
- codeframe/ui/routers/git_v2.py +284 -0
- codeframe/ui/routers/github_integrations_v2.py +532 -0
- codeframe/ui/routers/interactive_sessions_v2.py +238 -0
- codeframe/ui/routers/pr_v2.py +709 -0
- codeframe/ui/routers/prd_v2.py +695 -0
- codeframe/ui/routers/proof_v2.py +755 -0
- codeframe/ui/routers/review_v2.py +360 -0
- codeframe/ui/routers/schedule_v2.py +214 -0
- codeframe/ui/routers/session_chat_ws.py +354 -0
- codeframe/ui/routers/settings_v2.py +562 -0
- codeframe/ui/routers/streaming_v2.py +155 -0
- codeframe/ui/routers/tasks_v2.py +1098 -0
- codeframe/ui/routers/templates_v2.py +232 -0
- codeframe/ui/routers/terminal_ws.py +267 -0
- codeframe/ui/routers/workspace_v2.py +527 -0
- codeframe/ui/server.py +568 -0
- codeframe/ui/shared.py +241 -0
- codeframe/workspace/__init__.py +5 -0
- codeframe/workspace/manager.py +249 -0
- codeframe_ai-0.9.0.dist-info/METADATA +517 -0
- codeframe_ai-0.9.0.dist-info/RECORD +197 -0
- codeframe_ai-0.9.0.dist-info/WHEEL +5 -0
- codeframe_ai-0.9.0.dist-info/entry_points.txt +3 -0
- codeframe_ai-0.9.0.dist-info/licenses/LICENSE +661 -0
- codeframe_ai-0.9.0.dist-info/top_level.txt +1 -0
codeframe/core/hooks.py
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"""Workspace lifecycle hooks engine.
|
|
2
|
+
|
|
3
|
+
Executes shell commands at workspace lifecycle points (after_init, before_task,
|
|
4
|
+
after_task_success, after_task_failure, before_remove) with Jinja2 template
|
|
5
|
+
rendering and configurable timeouts.
|
|
6
|
+
|
|
7
|
+
Hook points:
|
|
8
|
+
- ``after_init``: Runs after ``cf init`` completes
|
|
9
|
+
- ``before_task``: Runs before agent execution (abort on failure)
|
|
10
|
+
- ``after_task_success``: Runs after successful task completion
|
|
11
|
+
- ``after_task_failure``: Runs after failed task execution
|
|
12
|
+
- ``before_remove``: Available for future workspace teardown
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
import shlex
|
|
19
|
+
import subprocess
|
|
20
|
+
import time
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import TYPE_CHECKING, Optional
|
|
24
|
+
|
|
25
|
+
from jinja2 import Template
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from codeframe.core.config import EnvironmentConfig
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
# Hook point names (for reference and future workspace teardown)
|
|
33
|
+
HOOK_AFTER_INIT = "after_init"
|
|
34
|
+
HOOK_BEFORE_TASK = "before_task"
|
|
35
|
+
HOOK_AFTER_TASK_SUCCESS = "after_task_success"
|
|
36
|
+
HOOK_AFTER_TASK_FAILURE = "after_task_failure"
|
|
37
|
+
HOOK_BEFORE_REMOVE = "before_remove"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class HookContext:
|
|
42
|
+
"""Template variables available to hook commands."""
|
|
43
|
+
|
|
44
|
+
task_id: str
|
|
45
|
+
task_title: str
|
|
46
|
+
task_status: str
|
|
47
|
+
workspace_path: str
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class HookResult:
|
|
52
|
+
"""Result from a hook execution."""
|
|
53
|
+
|
|
54
|
+
hook_name: str
|
|
55
|
+
command: str
|
|
56
|
+
success: bool
|
|
57
|
+
stdout: str
|
|
58
|
+
stderr: str
|
|
59
|
+
duration_ms: int
|
|
60
|
+
timed_out: bool
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class HookAbortError(Exception):
|
|
64
|
+
"""Raised when a before_* hook fails and should abort the operation."""
|
|
65
|
+
|
|
66
|
+
def __init__(self, hook_name: str, result: HookResult) -> None:
|
|
67
|
+
self.hook_name = hook_name
|
|
68
|
+
self.result = result
|
|
69
|
+
super().__init__(
|
|
70
|
+
f"Hook '{hook_name}' failed and aborted the operation: "
|
|
71
|
+
f"{result.stderr[:200]}"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def render_hook_command(template: str, ctx: HookContext) -> str:
|
|
76
|
+
"""Render a hook command template with context variables.
|
|
77
|
+
|
|
78
|
+
Variable values are shell-escaped to prevent injection via task_title
|
|
79
|
+
or other user-controlled fields.
|
|
80
|
+
"""
|
|
81
|
+
return Template(template).render(
|
|
82
|
+
task_id=shlex.quote(ctx.task_id),
|
|
83
|
+
task_title=shlex.quote(ctx.task_title),
|
|
84
|
+
task_status=shlex.quote(ctx.task_status),
|
|
85
|
+
workspace_path=shlex.quote(ctx.workspace_path),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def run_hook(
|
|
90
|
+
hook_name: str,
|
|
91
|
+
command: str,
|
|
92
|
+
workspace_path: Path,
|
|
93
|
+
ctx: HookContext,
|
|
94
|
+
timeout: int,
|
|
95
|
+
) -> HookResult:
|
|
96
|
+
"""Execute a hook command as a subprocess.
|
|
97
|
+
|
|
98
|
+
The command template is rendered with context variables before execution.
|
|
99
|
+
Runs with shell=True (hooks use shell operators like &&).
|
|
100
|
+
"""
|
|
101
|
+
rendered = render_hook_command(command, ctx)
|
|
102
|
+
start = time.monotonic()
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
proc = subprocess.run(
|
|
106
|
+
rendered,
|
|
107
|
+
shell=True,
|
|
108
|
+
cwd=str(workspace_path),
|
|
109
|
+
capture_output=True,
|
|
110
|
+
text=True,
|
|
111
|
+
timeout=timeout,
|
|
112
|
+
)
|
|
113
|
+
duration_ms = int((time.monotonic() - start) * 1000)
|
|
114
|
+
return HookResult(
|
|
115
|
+
hook_name=hook_name,
|
|
116
|
+
command=rendered,
|
|
117
|
+
success=proc.returncode == 0,
|
|
118
|
+
stdout=proc.stdout[:2000],
|
|
119
|
+
stderr=proc.stderr[:2000],
|
|
120
|
+
duration_ms=duration_ms,
|
|
121
|
+
timed_out=False,
|
|
122
|
+
)
|
|
123
|
+
except subprocess.TimeoutExpired:
|
|
124
|
+
duration_ms = int((time.monotonic() - start) * 1000)
|
|
125
|
+
return HookResult(
|
|
126
|
+
hook_name=hook_name,
|
|
127
|
+
command=rendered,
|
|
128
|
+
success=False,
|
|
129
|
+
stdout="",
|
|
130
|
+
stderr=f"Hook timed out after {timeout}s",
|
|
131
|
+
duration_ms=duration_ms,
|
|
132
|
+
timed_out=True,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def execute_hook(
|
|
137
|
+
hook_name: str,
|
|
138
|
+
config: EnvironmentConfig,
|
|
139
|
+
workspace_path: Path,
|
|
140
|
+
ctx: HookContext,
|
|
141
|
+
*,
|
|
142
|
+
abort_on_failure: bool,
|
|
143
|
+
) -> Optional[HookResult]:
|
|
144
|
+
"""Look up and execute a named hook from config.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
hook_name: One of the HOOK_* constants (e.g., "before_task")
|
|
148
|
+
config: EnvironmentConfig containing hooks section
|
|
149
|
+
workspace_path: Working directory for the subprocess
|
|
150
|
+
ctx: Template context variables
|
|
151
|
+
abort_on_failure: If True and hook fails, raise HookAbortError
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
HookResult if hook was configured and ran, None if not configured.
|
|
155
|
+
|
|
156
|
+
Raises:
|
|
157
|
+
HookAbortError: If abort_on_failure=True and the hook fails.
|
|
158
|
+
"""
|
|
159
|
+
command = getattr(config.hooks, hook_name, None)
|
|
160
|
+
if not command:
|
|
161
|
+
return None
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
result = run_hook(hook_name, command, workspace_path, ctx, config.hooks.hook_timeout)
|
|
165
|
+
except Exception as exc:
|
|
166
|
+
if abort_on_failure:
|
|
167
|
+
raise
|
|
168
|
+
logger.warning("Hook '%s' raised unexpected error (non-blocking): %s", hook_name, exc)
|
|
169
|
+
return HookResult(
|
|
170
|
+
hook_name=hook_name, command=command, success=False,
|
|
171
|
+
stdout="", stderr=str(exc), duration_ms=0, timed_out=False,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if not result.success:
|
|
175
|
+
if abort_on_failure:
|
|
176
|
+
raise HookAbortError(hook_name, result)
|
|
177
|
+
else:
|
|
178
|
+
logger.warning(
|
|
179
|
+
"Hook '%s' failed (non-blocking): %s",
|
|
180
|
+
hook_name,
|
|
181
|
+
result.stderr[:200],
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
return result
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Importers that migrate projects from other tools into CodeFRAME."""
|