xenfra-sdk 0.2.5__py3-none-any.whl → 0.2.6__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.
- xenfra_sdk/__init__.py +46 -2
- xenfra_sdk/blueprints/base.py +150 -0
- xenfra_sdk/blueprints/factory.py +99 -0
- xenfra_sdk/blueprints/node.py +219 -0
- xenfra_sdk/blueprints/python.py +57 -0
- xenfra_sdk/blueprints/railpack.py +99 -0
- xenfra_sdk/blueprints/schema.py +70 -0
- xenfra_sdk/cli/main.py +175 -49
- xenfra_sdk/client.py +6 -2
- xenfra_sdk/constants.py +26 -0
- xenfra_sdk/db/session.py +8 -3
- xenfra_sdk/detection.py +262 -191
- xenfra_sdk/dockerizer.py +76 -120
- xenfra_sdk/engine.py +758 -172
- xenfra_sdk/events.py +254 -0
- xenfra_sdk/exceptions.py +9 -0
- xenfra_sdk/governance.py +150 -0
- xenfra_sdk/manifest.py +93 -138
- xenfra_sdk/mcp_client.py +7 -5
- xenfra_sdk/{models.py → models/__init__.py} +17 -1
- xenfra_sdk/models/context.py +61 -0
- xenfra_sdk/orchestrator.py +223 -99
- xenfra_sdk/privacy.py +11 -0
- xenfra_sdk/protocol.py +38 -0
- xenfra_sdk/railpack_adapter.py +357 -0
- xenfra_sdk/railpack_detector.py +587 -0
- xenfra_sdk/railpack_manager.py +312 -0
- xenfra_sdk/recipes.py +152 -19
- xenfra_sdk/resources/activity.py +45 -0
- xenfra_sdk/resources/build.py +157 -0
- xenfra_sdk/resources/deployments.py +22 -2
- xenfra_sdk/resources/intelligence.py +25 -0
- xenfra_sdk-0.2.6.dist-info/METADATA +118 -0
- xenfra_sdk-0.2.6.dist-info/RECORD +49 -0
- {xenfra_sdk-0.2.5.dist-info → xenfra_sdk-0.2.6.dist-info}/WHEEL +1 -1
- xenfra_sdk/templates/Caddyfile.j2 +0 -14
- xenfra_sdk/templates/Dockerfile.j2 +0 -41
- xenfra_sdk/templates/cloud-init.sh.j2 +0 -90
- xenfra_sdk/templates/docker-compose-multi.yml.j2 +0 -29
- xenfra_sdk/templates/docker-compose.yml.j2 +0 -30
- xenfra_sdk-0.2.5.dist-info/METADATA +0 -116
- xenfra_sdk-0.2.5.dist-info/RECORD +0 -38
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Build resource manager for 3-tier dry-run validation.
|
|
3
|
+
|
|
4
|
+
Provides methods for:
|
|
5
|
+
- Tier 2: Build plan detection (Railpack)
|
|
6
|
+
- Tier 3: Sandbox validation (E2B via Xenfra API)
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Dict, List, Optional
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BuildManager:
|
|
13
|
+
"""Manager for build operations and dry-run validation."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, client):
|
|
16
|
+
"""
|
|
17
|
+
Initialize the BuildManager.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
client: The XenfraClient instance.
|
|
21
|
+
"""
|
|
22
|
+
self._client = client
|
|
23
|
+
|
|
24
|
+
def detect(self, file_manifest: List[Dict]) -> Dict:
|
|
25
|
+
"""
|
|
26
|
+
Tier 2: Detect build plan from project files.
|
|
27
|
+
|
|
28
|
+
Runs Railpack detection on the backend to determine
|
|
29
|
+
framework, language, and build configuration.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
file_manifest: List of file info dicts with keys: path, sha, size
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Dict with build plan:
|
|
36
|
+
- framework: str (fastapi, flask, nextjs, etc.)
|
|
37
|
+
- language: str (python, node, go, rust)
|
|
38
|
+
- package_manager: str (pip, npm, go mod, etc.)
|
|
39
|
+
- dependency_file: str (requirements.txt, package.json)
|
|
40
|
+
- port: int
|
|
41
|
+
- build_command: Optional[str]
|
|
42
|
+
- start_command: Optional[str]
|
|
43
|
+
- dockerfile: Optional[str] (generated if applicable)
|
|
44
|
+
"""
|
|
45
|
+
payload = {"files": file_manifest}
|
|
46
|
+
|
|
47
|
+
response = self._client._request("POST", "/build/detect", json=payload)
|
|
48
|
+
return response.json()
|
|
49
|
+
|
|
50
|
+
def validate(
|
|
51
|
+
self,
|
|
52
|
+
file_manifest: List[Dict],
|
|
53
|
+
build_plan: Dict,
|
|
54
|
+
timeout: int = 300
|
|
55
|
+
) -> Dict:
|
|
56
|
+
"""
|
|
57
|
+
Tier 3: Validate build in E2B sandbox.
|
|
58
|
+
|
|
59
|
+
Runs full build validation in an isolated sandbox environment.
|
|
60
|
+
This ensures the project actually builds and runs before deployment.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
file_manifest: List of file info dicts with keys: path, sha, size
|
|
64
|
+
build_plan: Build plan dict from detect()
|
|
65
|
+
timeout: Maximum time to wait for validation (seconds)
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Dict with validation result:
|
|
69
|
+
- success: bool
|
|
70
|
+
- output: str (build output logs)
|
|
71
|
+
- error: Optional[str] (error message if failed)
|
|
72
|
+
- build_time: float (seconds)
|
|
73
|
+
- verification_proof: str (SHA256 hash for compliance)
|
|
74
|
+
"""
|
|
75
|
+
payload = {
|
|
76
|
+
"files": file_manifest,
|
|
77
|
+
"build_plan": build_plan,
|
|
78
|
+
"timeout": timeout
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
response = self._client._request("POST", "/build/validate", json=payload)
|
|
82
|
+
return response.json()
|
|
83
|
+
|
|
84
|
+
def validate_stream(
|
|
85
|
+
self,
|
|
86
|
+
file_manifest: List[Dict],
|
|
87
|
+
build_plan: Dict,
|
|
88
|
+
timeout: int = 300
|
|
89
|
+
):
|
|
90
|
+
"""
|
|
91
|
+
Tier 3: Validate build with streaming logs.
|
|
92
|
+
|
|
93
|
+
Same as validate() but yields log lines in real-time.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
file_manifest: List of file info dicts
|
|
97
|
+
build_plan: Build plan dict from detect()
|
|
98
|
+
timeout: Maximum time to wait
|
|
99
|
+
|
|
100
|
+
Yields:
|
|
101
|
+
Dict with:
|
|
102
|
+
- type: "log" | "complete" | "error"
|
|
103
|
+
- data: str (log line) or dict (result)
|
|
104
|
+
"""
|
|
105
|
+
payload = {
|
|
106
|
+
"files": file_manifest,
|
|
107
|
+
"build_plan": build_plan,
|
|
108
|
+
"timeout": timeout,
|
|
109
|
+
"stream": True
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
with self._client._request(
|
|
113
|
+
"POST",
|
|
114
|
+
"/build/validate",
|
|
115
|
+
json=payload,
|
|
116
|
+
stream=True
|
|
117
|
+
) as response:
|
|
118
|
+
for line in response.iter_lines():
|
|
119
|
+
if line:
|
|
120
|
+
import json
|
|
121
|
+
yield json.loads(line)
|
|
122
|
+
|
|
123
|
+
def dry_run(
|
|
124
|
+
self,
|
|
125
|
+
file_manifest: List[Dict],
|
|
126
|
+
skip_sandbox: bool = False,
|
|
127
|
+
force_sandbox: bool = False
|
|
128
|
+
) -> Dict:
|
|
129
|
+
"""
|
|
130
|
+
Run full 3-tier dry-run validation.
|
|
131
|
+
|
|
132
|
+
This is a convenience method that runs all three tiers:
|
|
133
|
+
- Tier 1: Local validation (client-side)
|
|
134
|
+
- Tier 2: Build detection (API call)
|
|
135
|
+
- Tier 3: Sandbox validation (API call, if needed)
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
file_manifest: List of file info dicts
|
|
139
|
+
skip_sandbox: Skip Tier 3 validation
|
|
140
|
+
force_sandbox: Force Tier 3 even if not needed
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Dict with full validation results:
|
|
144
|
+
- tier1: Dict (local validation result)
|
|
145
|
+
- tier2: Dict (build plan)
|
|
146
|
+
- tier3: Optional[Dict] (sandbox result)
|
|
147
|
+
- tier3_ran: bool
|
|
148
|
+
- success: bool
|
|
149
|
+
"""
|
|
150
|
+
payload = {
|
|
151
|
+
"files": file_manifest,
|
|
152
|
+
"skip_sandbox": skip_sandbox,
|
|
153
|
+
"force_sandbox": force_sandbox
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
response = self._client._request("POST", "/build/dry-run", json=payload)
|
|
157
|
+
return response.json()
|
|
@@ -12,7 +12,7 @@ logger = logging.getLogger(__name__)
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class DeploymentsManager(BaseManager):
|
|
15
|
-
def create(self, project_name: str, git_repo: str, branch: str, framework: str, region: str = None, size_slug: str = None, is_dockerized: bool = True, port: int = None, command: str = None, entrypoint: str = None, database: str = None, package_manager: str = None, dependency_file: str = None, file_manifest: list = None, cleanup_on_failure: bool = False, services: list = None, mode: str = None) -> dict:
|
|
15
|
+
def create(self, project_name: str, git_repo: str, branch: str, framework: str, region: str = None, size_slug: str = None, is_dockerized: bool = True, port: int = None, command: str = None, entrypoint: str = None, database: str = None, package_manager: str = None, dependency_file: str = None, file_manifest: list = None, cleanup_on_failure: bool = False, services: list = None, mode: str = None, verify_local: bool = True) -> dict:
|
|
16
16
|
"""Creates a new deployment."""
|
|
17
17
|
try:
|
|
18
18
|
payload = {
|
|
@@ -48,6 +48,8 @@ class DeploymentsManager(BaseManager):
|
|
|
48
48
|
payload["services"] = services
|
|
49
49
|
if mode:
|
|
50
50
|
payload["mode"] = mode
|
|
51
|
+
if verify_local is not None:
|
|
52
|
+
payload["verify_local"] = verify_local
|
|
51
53
|
|
|
52
54
|
response = self._client._request("POST", "/deployments", json=payload)
|
|
53
55
|
# Safe JSON parsing
|
|
@@ -118,7 +120,7 @@ class DeploymentsManager(BaseManager):
|
|
|
118
120
|
except Exception as e:
|
|
119
121
|
raise XenfraError(f"Failed to get logs for deployment {deployment_id}: {e}")
|
|
120
122
|
|
|
121
|
-
def create_stream(self, project_name: str, git_repo: str, branch: str, framework: str, region: str = None, size_slug: str = None, is_dockerized: bool = True, port: int = None, command: str = None, entrypoint: str = None, database: str = None, package_manager: str = None, dependency_file: str = None, file_manifest: list = None, cleanup_on_failure: bool = False, services: list = None, mode: str = None) -> Iterator[dict]:
|
|
123
|
+
def create_stream(self, project_name: str, git_repo: str, branch: str, framework: str, region: str = None, size_slug: str = None, is_dockerized: bool = True, port: int = None, command: str = None, entrypoint: str = None, database: str = None, package_manager: str = None, dependency_file: str = None, file_manifest: list = None, cleanup_on_failure: bool = False, services: list = None, mode: str = None, verify_local: bool = True) -> Iterator[dict]:
|
|
122
124
|
"""
|
|
123
125
|
Creates a new deployment with real-time SSE log streaming.
|
|
124
126
|
|
|
@@ -186,6 +188,8 @@ class DeploymentsManager(BaseManager):
|
|
|
186
188
|
payload["services"] = services
|
|
187
189
|
if mode:
|
|
188
190
|
payload["mode"] = mode
|
|
191
|
+
if verify_local is not None:
|
|
192
|
+
payload["verify_local"] = verify_local
|
|
189
193
|
|
|
190
194
|
try:
|
|
191
195
|
# Use httpx to stream the SSE response
|
|
@@ -276,3 +280,19 @@ class DeploymentsManager(BaseManager):
|
|
|
276
280
|
raise XenfraError(f"HTTP error during streaming deployment: {e}")
|
|
277
281
|
except Exception as e:
|
|
278
282
|
raise XenfraError(f"Failed to create streaming deployment: {e}")
|
|
283
|
+
|
|
284
|
+
def list(self) -> list[dict]:
|
|
285
|
+
"""
|
|
286
|
+
Retrieves a list of all deployments for the current user.
|
|
287
|
+
"""
|
|
288
|
+
try:
|
|
289
|
+
response = self._client._request("GET", "/deployments/list")
|
|
290
|
+
logger.debug(
|
|
291
|
+
f"DeploymentsManager.list response: status={response.status_code}"
|
|
292
|
+
)
|
|
293
|
+
# Safe JSON parsing
|
|
294
|
+
return safe_json_parse(response)
|
|
295
|
+
except XenfraAPIError:
|
|
296
|
+
raise
|
|
297
|
+
except Exception as e:
|
|
298
|
+
raise XenfraError(f"Failed to list deployments: {e}")
|
|
@@ -69,6 +69,31 @@ class IntelligenceManager(BaseManager):
|
|
|
69
69
|
except Exception as e:
|
|
70
70
|
raise XenfraError(f"Failed to diagnose logs: {e}")
|
|
71
71
|
|
|
72
|
+
def verify(
|
|
73
|
+
self,
|
|
74
|
+
logs: str,
|
|
75
|
+
code_snippets: list[dict[str, str]] | None = None,
|
|
76
|
+
) -> dict:
|
|
77
|
+
"""
|
|
78
|
+
Trigger the Secure Ralph Loop to verify and fix a failure.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
logs: The deployment logs to analyze
|
|
82
|
+
code_snippets: Optional list of [{"path": "...", "content": "..."}] for context
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Dictionary with status and final_fix if found
|
|
86
|
+
"""
|
|
87
|
+
try:
|
|
88
|
+
payload = {"logs": logs}
|
|
89
|
+
if code_snippets:
|
|
90
|
+
payload["code_snippets"] = code_snippets
|
|
91
|
+
|
|
92
|
+
response = self._client._request("POST", "/intelligence/verify", json=payload)
|
|
93
|
+
return safe_json_parse(response)
|
|
94
|
+
except Exception as e:
|
|
95
|
+
raise XenfraError(f"Verification gate failure: {e}")
|
|
96
|
+
|
|
72
97
|
def analyze_codebase(self, code_snippets: dict[str, str]) -> CodebaseAnalysisResponse:
|
|
73
98
|
"""
|
|
74
99
|
Analyze codebase to detect framework, dependencies, and deployment config.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: xenfra-sdk
|
|
3
|
+
Version: 0.2.6
|
|
4
|
+
Summary: Xenfra SDK: Core engine and utilities for the Xenfra platform.
|
|
5
|
+
Author: xenfra-cloud
|
|
6
|
+
Author-email: xenfra-cloud <xenfracloud@gmail.com>
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
13
|
+
Classifier: Topic :: System :: Systems Administration
|
|
14
|
+
Requires-Dist: fabric>=3.2.2
|
|
15
|
+
Requires-Dist: python-digitalocean>=1.17.0
|
|
16
|
+
Requires-Dist: python-dotenv>=1.2.1
|
|
17
|
+
Requires-Dist: rich>=14.2.0
|
|
18
|
+
Requires-Dist: sqlmodel>=0.0.16
|
|
19
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
20
|
+
Requires-Dist: httpx>=0.27.0
|
|
21
|
+
Requires-Dist: jinja2>=3.1.3
|
|
22
|
+
Requires-Dist: python-jose[cryptography]>=3.3.0
|
|
23
|
+
Requires-Dist: passlib>=1.7.4
|
|
24
|
+
Requires-Dist: cryptography>=41.0.0
|
|
25
|
+
Requires-Python: >=3.13
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# Xenfra Python SDK
|
|
29
|
+
|
|
30
|
+
The official, open-source Python SDK for interacting with the Xenfra API.
|
|
31
|
+
|
|
32
|
+
This SDK provides a simple and Pythonic interface for developers and AI Agents to programmatically manage infrastructure, deployments, and other platform resources.
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install xenfra-sdk
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Basic Usage
|
|
41
|
+
|
|
42
|
+
Initialize the client with your API token (or ensure the `XENFRA_TOKEN` environment variable is set).
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import os
|
|
46
|
+
from xenfra_sdk import XenfraClient
|
|
47
|
+
from xenfra_sdk.exceptions import XenfraAPIError
|
|
48
|
+
|
|
49
|
+
client = XenfraClient(token=os.getenv("XENFRA_TOKEN"))
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
projects = client.projects.list()
|
|
53
|
+
for p in projects:
|
|
54
|
+
print(f"Found project: {p.name} (Status: {p.status})")
|
|
55
|
+
except XenfraAPIError as e:
|
|
56
|
+
print(f"API Error: {e.detail}")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Usage for Agentic Workflows
|
|
60
|
+
|
|
61
|
+
The Xenfra SDK is designed to be used as a "tool" by AI Agents (e.g., OpenAI Assistants). The Pydantic models are compatible with function-calling schemas, allowing an agent to easily call these methods.
|
|
62
|
+
|
|
63
|
+
Here is a conceptual example of how an agent might use the SDK to fulfill a user's request.
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
# This is a conceptual representation of an agent's internal logic.
|
|
67
|
+
# The agent would be configured with functions that call these SDK methods.
|
|
68
|
+
|
|
69
|
+
def list_all_projects():
|
|
70
|
+
"""Lists all available projects in the Xenfra account."""
|
|
71
|
+
return client.projects.list()
|
|
72
|
+
|
|
73
|
+
def create_new_deployment(project_name: str, git_repo: str, branch: str = "main"):
|
|
74
|
+
"""
|
|
75
|
+
Creates a new deployment for a project.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
project_name: The name for the new deployment.
|
|
79
|
+
git_repo: The URL of the git repository to deploy.
|
|
80
|
+
branch: The branch to deploy (defaults to 'main').
|
|
81
|
+
"""
|
|
82
|
+
return client.deployments.create(
|
|
83
|
+
project_name=project_name,
|
|
84
|
+
git_repo=git_repo,
|
|
85
|
+
branch=branch,
|
|
86
|
+
framework="fastapi" # Framework detection would be part of a more complex agent
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# --- Agent Execution Flow ---
|
|
90
|
+
|
|
91
|
+
# User prompt: "Deploy my new app from github.com/user/my-app"
|
|
92
|
+
|
|
93
|
+
# 1. Agent decides which tool to use: `create_new_deployment`
|
|
94
|
+
# 2. Agent extracts parameters:
|
|
95
|
+
# - project_name = "my-app" (inferred)
|
|
96
|
+
# - git_repo = "https://github.com/user/my-app"
|
|
97
|
+
# 3. Agent calls the tool:
|
|
98
|
+
# create_new_deployment(
|
|
99
|
+
# project_name="my-app",
|
|
100
|
+
# git_repo="https://github.com/user/my-app"
|
|
101
|
+
# )
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Error Handling
|
|
105
|
+
|
|
106
|
+
The SDK uses custom exceptions for clear error handling. All API-related errors will raise a `XenfraAPIError`, which contains the `status_code` and a `detail` message from the API response.
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from xenfra_sdk.exceptions import XenfraAPIError, AuthenticationError
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
# Make an API call
|
|
113
|
+
...
|
|
114
|
+
except AuthenticationError as e:
|
|
115
|
+
print("Authentication failed. Please check your token.")
|
|
116
|
+
except XenfraAPIError as e:
|
|
117
|
+
print(f"An API error occurred with status {e.status_code}: {e.detail}")
|
|
118
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
xenfra_sdk/__init__.py,sha256=GGdls_QuRYtRlI3O2p0gGjfA93C4X7NpjvSEdhPIDas,2451
|
|
2
|
+
xenfra_sdk/blueprints/base.py,sha256=AChTct80KC6LoYwsY6DcGLIWbTY14VDaNVtOmpjr_Zs,5742
|
|
3
|
+
xenfra_sdk/blueprints/factory.py,sha256=BGyl9DUoHuB8Y5dU_syAg9a6kwWyzYHDdd7rKi6EHo8,4197
|
|
4
|
+
xenfra_sdk/blueprints/node.py,sha256=kS2AxeET_-qokJmCR_lvCn3gu0dI3ck7ymdC6HOZHlY,8108
|
|
5
|
+
xenfra_sdk/blueprints/python.py,sha256=9HrNXhQkRqEa_BlsMlm8cf3qP4-4DCNtaqHKWGsYIFo,2416
|
|
6
|
+
xenfra_sdk/blueprints/railpack.py,sha256=JfIfkWEw4U5Yid4BNCFELGZm82jfCyTjaL8hcSn6T0I,3518
|
|
7
|
+
xenfra_sdk/blueprints/schema.py,sha256=DuJlCTaGNIRA789_V8r98TbMU4cq53FY89QrSdcA4Fs,3154
|
|
8
|
+
xenfra_sdk/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
xenfra_sdk/cli/main.py,sha256=UqYz1Ai9aVc8goqtjUtMtffeENPvjH_KAj_q_nHBuRI,13690
|
|
10
|
+
xenfra_sdk/client.py,sha256=9QqFXwtrk4cpIQLQ6IIshAG3LM4LFQMgV-T6Ub3aIy0,3890
|
|
11
|
+
xenfra_sdk/client_with_hooks.py,sha256=iN-xTGdeSPizktM6UG-aZEsuwQc5OgosNYUf1_Tq4Dc,10046
|
|
12
|
+
xenfra_sdk/config.py,sha256=gaT4k5iJgW9guNVmlnYkCFGDSU1_er4LRZA2CgfKmJ0,588
|
|
13
|
+
xenfra_sdk/constants.py,sha256=NFZXuZUl-ANMYfBfKnDpPJOJtRHbDo-VDN0k0MKNjfs,873
|
|
14
|
+
xenfra_sdk/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
xenfra_sdk/db/models.py,sha256=nbnlNiFShUo9uxrcVLHUezlNtF_NATS85pPYTKBriIE,714
|
|
16
|
+
xenfra_sdk/db/session.py,sha256=Cryt02u01Lq_olwOji3X9a5pI7lE5p0O0mKX3na9h6M,879
|
|
17
|
+
xenfra_sdk/dependencies.py,sha256=WHGfIrEYkss5yuBd_uOFrB6lPBWM2X0mEuG26ILAjXI,1211
|
|
18
|
+
xenfra_sdk/detection.py,sha256=7DDfwOAfmZYF5tzJAcbUsME8alfsqS0HQgrI4eTfwTA,18913
|
|
19
|
+
xenfra_sdk/dockerizer.py,sha256=iSn-HZ2-07zgM-C2aQkJH-MBtPrkEimurKLY9hth34Y,5191
|
|
20
|
+
xenfra_sdk/engine.py,sha256=nmrjFKaYsouHvfFThYo4gXTuoCr0Xr2zgFy35XcfIKo,67310
|
|
21
|
+
xenfra_sdk/events.py,sha256=7BgtTc4a-bw6ybicQblQ-Y0CGbUpgR_Cx4YNaJi_SsU,8013
|
|
22
|
+
xenfra_sdk/exceptions.py,sha256=rNUpuk6NXsigqBUNMqzit48DjvZev5Try87zVT8ethE,753
|
|
23
|
+
xenfra_sdk/governance.py,sha256=g9bN174HeoA13Cv-8o6hoVK_dRcrnHOBVRdKkZE9pWY,3784
|
|
24
|
+
xenfra_sdk/manifest.py,sha256=ymAvih83VzKcrMxIpNGnffg0TtxCowiPUgvYx4qks6E,6210
|
|
25
|
+
xenfra_sdk/mcp_client.py,sha256=QTKu-gkm0oeYOyCyXweZgxEXA3DvBLwQxEaNMevBBzw,5869
|
|
26
|
+
xenfra_sdk/models/__init__.py,sha256=Ek5AT--i6oIKUjQJJGNQiLLwkLieMm4w9do4h7XwoGc,8174
|
|
27
|
+
xenfra_sdk/models/context.py,sha256=ByQofUAKqDRqJ7HZoiVLXnfuw6X0cWhsuMlUrV9Bix0,2341
|
|
28
|
+
xenfra_sdk/orchestrator.py,sha256=2vd1YCQX6pVsa1wtdhRD4Xo4Nscmxt2_1_sjKw39CGw,34006
|
|
29
|
+
xenfra_sdk/patterns.json,sha256=xHxbc0ogHDwysMczi30_hW1Ylfdsf-nsQdAom7RZ4KI,446
|
|
30
|
+
xenfra_sdk/privacy.py,sha256=YpV8roCX2C2oLY_6TMXSDISuzNb192RuUPriwORKzNQ,5800
|
|
31
|
+
xenfra_sdk/protocol.py,sha256=nVamJTzEAKk71v-MUR_5yvkxMkMzR5Crmp9ecbqLVhI,1210
|
|
32
|
+
xenfra_sdk/railpack_adapter.py,sha256=whS5KmFioLOkciRNst6L76tccuDPRIIEpZ-saeC0q-Y,14799
|
|
33
|
+
xenfra_sdk/railpack_detector.py,sha256=Z8lMuwDpvne1VviKHdLu0VgLCNJ45bFXk4w1-tYRD6c,21540
|
|
34
|
+
xenfra_sdk/railpack_manager.py,sha256=PVVwAxVaQtiMRAafCx4s3sEqMdSgRUuYe2gUm-x21VI,11335
|
|
35
|
+
xenfra_sdk/recipes.py,sha256=RA1R8fUb5ZiEStcO8451P8fiQ4zaKZWO_ianTl1X1Zk,6608
|
|
36
|
+
xenfra_sdk/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
|
+
xenfra_sdk/resources/activity.py,sha256=Xpopc6bcJMyae6Bcq813GxiA4laVUF-gHDPq-F4acHE,1709
|
|
38
|
+
xenfra_sdk/resources/base.py,sha256=5n-HTKAnIX2lTgXwio0xtwoaBn-nksjdm8qRTpe3iDk,81
|
|
39
|
+
xenfra_sdk/resources/build.py,sha256=s7_VHeMIWrn1JhDQAeTq1kLeB0gFagHm9JVroTHpUqM,5024
|
|
40
|
+
xenfra_sdk/resources/deployments.py,sha256=VjTUn0TZyGUEvEsgy7TUa4T4VZH_IPr7IV4-seDfg6w,12736
|
|
41
|
+
xenfra_sdk/resources/files.py,sha256=opdxZt6GWMU-qu5ltfWfv2hm8TscdaK-r9o4k743Irs,3087
|
|
42
|
+
xenfra_sdk/resources/intelligence.py,sha256=oD8DxyLxivvTrD-Xvv1pDJtKsZkiTOOwIMenZAssbzI,4397
|
|
43
|
+
xenfra_sdk/resources/projects.py,sha256=EsCVXmqkhWl_Guz_8WDQDi3kAm1Wyg1rjXcyAigPD6E,3712
|
|
44
|
+
xenfra_sdk/security.py,sha256=6vMZpbglhkRGBVVj4RCTu45-MCnQ15wt94-996zmaT8,1199
|
|
45
|
+
xenfra_sdk/security_scanner.py,sha256=US9QdMjHdTUkqObrGPHvDPxMP0QXCxmwK5e28d8KT2E,12957
|
|
46
|
+
xenfra_sdk/utils.py,sha256=d8eCjjV32QwqoJa759CEcETnnsjG5qVKDLQ84yYtlus,3898
|
|
47
|
+
xenfra_sdk-0.2.6.dist-info/WHEEL,sha256=5DEXXimM34_d4Gx1AuF9ysMr1_maoEtGKjaILM3s4w4,80
|
|
48
|
+
xenfra_sdk-0.2.6.dist-info/METADATA,sha256=PsSEAuYqDKMuXabOgzvPOY_E80jdsDFjSyw_3JdNIRo,3889
|
|
49
|
+
xenfra_sdk-0.2.6.dist-info/RECORD,,
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Caddyfile template for multi-service routing
|
|
2
|
-
# Generated by Xenfra for microservices deployments
|
|
3
|
-
|
|
4
|
-
:80 {
|
|
5
|
-
{% for service in services %}
|
|
6
|
-
route /{{ service.name }}* {
|
|
7
|
-
reverse_proxy localhost:{{ service.port }}
|
|
8
|
-
}
|
|
9
|
-
{% endfor %}
|
|
10
|
-
|
|
11
|
-
route / {
|
|
12
|
-
respond "Xenfra Gateway - {{ project_name }}" 200
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Dockerfile template for Python web applications
|
|
2
|
-
FROM {{ python_version | default('python:3.11-slim') }}
|
|
3
|
-
|
|
4
|
-
WORKDIR /app
|
|
5
|
-
|
|
6
|
-
{% if package_manager != 'pip' %}
|
|
7
|
-
# Install uv package manager and add to PATH
|
|
8
|
-
RUN apt-get update && apt-get install -y curl && \
|
|
9
|
-
curl -LsSf https://astral.sh/uv/install.sh | sh && \
|
|
10
|
-
apt-get remove -y curl && \
|
|
11
|
-
apt-get clean && \
|
|
12
|
-
rm -rf /var/lib/apt/lists/*
|
|
13
|
-
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
|
14
|
-
{% endif %}
|
|
15
|
-
|
|
16
|
-
{% if dependency_file == 'pyproject.toml' %}
|
|
17
|
-
# For pyproject.toml, copy all files first (hatchling needs README.md etc.)
|
|
18
|
-
COPY . .
|
|
19
|
-
|
|
20
|
-
# Install dependencies
|
|
21
|
-
RUN uv pip install --system --no-cache .
|
|
22
|
-
{% else %}
|
|
23
|
-
COPY {{ dependency_file | default('requirements.txt') }} .
|
|
24
|
-
|
|
25
|
-
# Install dependencies
|
|
26
|
-
{% if package_manager == 'pip' %}
|
|
27
|
-
RUN pip install --no-cache-dir -r {{ dependency_file | default('requirements.txt') }}
|
|
28
|
-
{% endif %}
|
|
29
|
-
|
|
30
|
-
{% if missing_deps %}
|
|
31
|
-
# Auto-heal missing dependencies (Zen Mode)
|
|
32
|
-
RUN pip install --no-cache-dir {{ missing_deps | join(' ') }}
|
|
33
|
-
{% endif %}
|
|
34
|
-
|
|
35
|
-
COPY . .
|
|
36
|
-
{% endif %}
|
|
37
|
-
|
|
38
|
-
# Expose the application port
|
|
39
|
-
EXPOSE {{ port | default(8000) }}
|
|
40
|
-
|
|
41
|
-
# The command to run the application will be in docker-compose.yml
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
export DEBIAN_FRONTEND=noninteractive
|
|
3
|
-
LOG="/root/setup.log"
|
|
4
|
-
touch $LOG
|
|
5
|
-
|
|
6
|
-
echo "--------------------------------" >> $LOG
|
|
7
|
-
echo "🧘 XENFRA: Context-Aware Boot" >> $LOG
|
|
8
|
-
echo "--------------------------------" >> $LOG
|
|
9
|
-
|
|
10
|
-
# Create App Directory
|
|
11
|
-
mkdir -p /root/app
|
|
12
|
-
cd /root/app
|
|
13
|
-
|
|
14
|
-
# --- MERCILESS FIX: TERMINATE BACKGROUND PROCESSES ---
|
|
15
|
-
echo "⚔️ [0/6] Mercilessly Terminating Background Processes..." >> $LOG
|
|
16
|
-
|
|
17
|
-
kill_apt_processes() {
|
|
18
|
-
echo "🎯 Killing processes holding apt/dpkg locks..." >> $LOG
|
|
19
|
-
fuser -k /var/lib/dpkg/lock >/dev/null 2>&1
|
|
20
|
-
fuser -k /var/lib/apt/lists/lock >/dev/null 2>&1
|
|
21
|
-
fuser -k /var/lib/dpkg/lock-frontends >/dev/null 2>&1
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
# Explicitly stop and disable services that cause locks
|
|
25
|
-
systemctl stop unattended-upgrades.service || true
|
|
26
|
-
systemctl disable unattended-upgrades.service || true
|
|
27
|
-
systemctl stop apt-daily.service || true
|
|
28
|
-
systemctl disable apt-daily.service || true
|
|
29
|
-
systemctl stop apt-daily-upgrade.service || true
|
|
30
|
-
systemctl disable apt-daily-upgrade.service || true
|
|
31
|
-
|
|
32
|
-
# Forcefully kill any remaining lock holders
|
|
33
|
-
kill_apt_processes
|
|
34
|
-
|
|
35
|
-
# Force remove locks if they still exist (The Nuclear Option)
|
|
36
|
-
rm -f /var/lib/dpkg/lock*
|
|
37
|
-
rm -f /var/lib/apt/lists/lock*
|
|
38
|
-
rm -f /var/cache/apt/archives/lock
|
|
39
|
-
dpkg --configure -a || true
|
|
40
|
-
# -----------------------------------------------
|
|
41
|
-
|
|
42
|
-
# 1. System Updates
|
|
43
|
-
echo "🔄 [1/5] Refreshing Package Lists..." >> $LOG
|
|
44
|
-
apt-get update
|
|
45
|
-
apt-get install -y python3-pip git curl
|
|
46
|
-
|
|
47
|
-
# 2. Setup Environment
|
|
48
|
-
{% if is_dockerized %}
|
|
49
|
-
echo "🐳 [2/5] Installing Docker..." >> $LOG
|
|
50
|
-
apt-get install -y docker.io || (curl -fsSL https://get.docker.com | sh)
|
|
51
|
-
echo "🎶 [3/5] Installing Docker Compose..." >> $LOG
|
|
52
|
-
apt-get install -y docker-compose-v2
|
|
53
|
-
{% else %}
|
|
54
|
-
echo "🐍 [2/5] Setting up host-based Python environment..." >> $LOG
|
|
55
|
-
apt-get install -y python3-venv python3-dev build-essential
|
|
56
|
-
{% endif %}
|
|
57
|
-
|
|
58
|
-
# 3. Setup Reverse Proxy
|
|
59
|
-
{% if is_dockerized or install_caddy %}
|
|
60
|
-
echo "📦 [3/5] Installing Caddy..." >> $LOG
|
|
61
|
-
apt-get install -y debian-keyring debian-archive-keyring apt-transport-https
|
|
62
|
-
curl -LsSf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
|
|
63
|
-
curl -LsSf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
|
|
64
|
-
apt-get update
|
|
65
|
-
apt-get install -y caddy
|
|
66
|
-
{% else %}
|
|
67
|
-
echo "🛡️ [3/5] Skipping Caddy for host deployment (setup manual reverse proxy if needed)." >> $LOG
|
|
68
|
-
{% endif %}
|
|
69
|
-
|
|
70
|
-
{% if domain %}
|
|
71
|
-
# Dynamically generate Caddyfile content
|
|
72
|
-
echo "🔒 Writing Caddyfile for {{ domain }}..." >> $LOG
|
|
73
|
-
cat << EOF > /etc/caddy/Caddyfile
|
|
74
|
-
{{ domain }}:80, {{ domain }}:443 {
|
|
75
|
-
reverse_proxy localhost:{{ port | default(8000) }}
|
|
76
|
-
tls {{ email }}
|
|
77
|
-
}
|
|
78
|
-
EOF
|
|
79
|
-
{% endif %}
|
|
80
|
-
|
|
81
|
-
{% if domain %}
|
|
82
|
-
echo "🚀 [5/5] Starting Caddy..." >> $LOG
|
|
83
|
-
systemctl restart caddy
|
|
84
|
-
{% else %}
|
|
85
|
-
echo "✅ [5/5] Skipping Caddy start (no domain specified)." >> $LOG
|
|
86
|
-
{% endif %}
|
|
87
|
-
|
|
88
|
-
# Finish
|
|
89
|
-
echo "✅ SETUP SCRIPT COMPLETE" >> $LOG
|
|
90
|
-
touch /root/setup_complete
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# docker-compose.yml template for multi-service deployments
|
|
2
|
-
# Generated by Xenfra for microservices
|
|
3
|
-
|
|
4
|
-
services:
|
|
5
|
-
{% for service in services %}
|
|
6
|
-
{{ service.name }}:
|
|
7
|
-
build: {{ service.path }}
|
|
8
|
-
ports:
|
|
9
|
-
- "{{ service.port }}:{{ service.port }}"
|
|
10
|
-
{% if service.command %}
|
|
11
|
-
command: {{ service.command }}
|
|
12
|
-
{% elif service.entrypoint %}
|
|
13
|
-
{% if service.framework == 'fastapi' %}
|
|
14
|
-
command: uvicorn {{ service.entrypoint }} --host 0.0.0.0 --port {{ service.port }}
|
|
15
|
-
{% elif service.framework == 'flask' %}
|
|
16
|
-
command: gunicorn {{ service.entrypoint }} -b 0.0.0.0:{{ service.port }}
|
|
17
|
-
{% elif service.framework == 'django' %}
|
|
18
|
-
command: gunicorn {{ service.entrypoint }} --bind 0.0.0.0:{{ service.port }}
|
|
19
|
-
{% endif %}
|
|
20
|
-
{% endif %}
|
|
21
|
-
{% if service.env %}
|
|
22
|
-
environment:
|
|
23
|
-
{% for key, value in service.env.items() %}
|
|
24
|
-
- {{ key }}={{ value }}
|
|
25
|
-
{% endfor %}
|
|
26
|
-
{% endif %}
|
|
27
|
-
restart: unless-stopped
|
|
28
|
-
|
|
29
|
-
{% endfor %}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# docker-compose.yml template
|
|
2
|
-
|
|
3
|
-
services:
|
|
4
|
-
app:
|
|
5
|
-
build: .
|
|
6
|
-
ports:
|
|
7
|
-
- "{{ port | default(8000) }}:{{ port | default(8000) }}"
|
|
8
|
-
{% if command and command != 'None' %}
|
|
9
|
-
command: {{ command }}
|
|
10
|
-
{% else %}
|
|
11
|
-
command: ["uvicorn", "{{ entrypoint | default('src.main:app') }}", "--host", "0.0.0.0", "--port", "{{ port | default(8000) }}"]
|
|
12
|
-
{% endif %}
|
|
13
|
-
{% if database == 'postgres' or database == 'postgresql' %}
|
|
14
|
-
depends_on:
|
|
15
|
-
- db
|
|
16
|
-
environment:
|
|
17
|
-
- DATABASE_URL=postgresql://{{ db_user | default('user') }}:{{ db_password | default('password') }}@db:5432/{{ db_name | default('appdb') }}
|
|
18
|
-
|
|
19
|
-
db:
|
|
20
|
-
image: postgres:15-alpine
|
|
21
|
-
volumes:
|
|
22
|
-
- postgres_data:/var/lib/postgresql/data/
|
|
23
|
-
environment:
|
|
24
|
-
- POSTGRES_USER={{ db_user | default('user') }}
|
|
25
|
-
- POSTGRES_PASSWORD={{ db_password | default('password') }}
|
|
26
|
-
- POSTGRES_DB={{ db_name | default('appdb') }}
|
|
27
|
-
|
|
28
|
-
volumes:
|
|
29
|
-
postgres_data:
|
|
30
|
-
{% endif %}
|