xenfra-sdk 0.2.4__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.
Files changed (43) hide show
  1. xenfra_sdk/__init__.py +46 -2
  2. xenfra_sdk/blueprints/base.py +150 -0
  3. xenfra_sdk/blueprints/factory.py +99 -0
  4. xenfra_sdk/blueprints/node.py +219 -0
  5. xenfra_sdk/blueprints/python.py +57 -0
  6. xenfra_sdk/blueprints/railpack.py +99 -0
  7. xenfra_sdk/blueprints/schema.py +70 -0
  8. xenfra_sdk/cli/main.py +175 -49
  9. xenfra_sdk/client.py +6 -2
  10. xenfra_sdk/constants.py +26 -0
  11. xenfra_sdk/db/models.py +2 -0
  12. xenfra_sdk/db/session.py +8 -3
  13. xenfra_sdk/detection.py +262 -191
  14. xenfra_sdk/dockerizer.py +76 -120
  15. xenfra_sdk/engine.py +762 -160
  16. xenfra_sdk/events.py +254 -0
  17. xenfra_sdk/exceptions.py +9 -0
  18. xenfra_sdk/governance.py +150 -0
  19. xenfra_sdk/manifest.py +93 -138
  20. xenfra_sdk/mcp_client.py +7 -5
  21. xenfra_sdk/{models.py → models/__init__.py} +17 -1
  22. xenfra_sdk/models/context.py +61 -0
  23. xenfra_sdk/orchestrator.py +223 -99
  24. xenfra_sdk/privacy.py +11 -0
  25. xenfra_sdk/protocol.py +38 -0
  26. xenfra_sdk/railpack_adapter.py +357 -0
  27. xenfra_sdk/railpack_detector.py +587 -0
  28. xenfra_sdk/railpack_manager.py +312 -0
  29. xenfra_sdk/recipes.py +152 -19
  30. xenfra_sdk/resources/activity.py +45 -0
  31. xenfra_sdk/resources/build.py +157 -0
  32. xenfra_sdk/resources/deployments.py +22 -2
  33. xenfra_sdk/resources/intelligence.py +25 -0
  34. xenfra_sdk-0.2.6.dist-info/METADATA +118 -0
  35. xenfra_sdk-0.2.6.dist-info/RECORD +49 -0
  36. {xenfra_sdk-0.2.4.dist-info → xenfra_sdk-0.2.6.dist-info}/WHEEL +1 -1
  37. xenfra_sdk/templates/Caddyfile.j2 +0 -14
  38. xenfra_sdk/templates/Dockerfile.j2 +0 -41
  39. xenfra_sdk/templates/cloud-init.sh.j2 +0 -90
  40. xenfra_sdk/templates/docker-compose-multi.yml.j2 +0 -29
  41. xenfra_sdk/templates/docker-compose.yml.j2 +0 -30
  42. xenfra_sdk-0.2.4.dist-info/METADATA +0 -116
  43. xenfra_sdk-0.2.4.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,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.9.26
2
+ Generator: uv 0.9.29
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -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 %}