xenfra-sdk 0.1.2__py3-none-any.whl → 0.1.4__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.
@@ -1,95 +1,95 @@
1
- """
2
- Intelligence resource manager for Xenfra SDK.
3
- Provides AI-powered deployment diagnosis and codebase analysis.
4
- """
5
-
6
- import logging
7
-
8
- from ..exceptions import XenfraAPIError, XenfraError
9
- from ..models import CodebaseAnalysisResponse, DiagnosisResponse
10
- from ..utils import safe_json_parse
11
- from .base import BaseManager
12
-
13
- logger = logging.getLogger(__name__)
14
-
15
-
16
- class IntelligenceManager(BaseManager):
17
- """
18
- Manager for AI-powered intelligence operations.
19
-
20
- Provides:
21
- - Deployment failure diagnosis (Zen Nod)
22
- - Codebase analysis for zero-config init (Zen Init)
23
- """
24
-
25
- def diagnose(
26
- self, logs: str, package_manager: str | None = None, dependency_file: str | None = None
27
- ) -> DiagnosisResponse:
28
- """
29
- Diagnose deployment failure from logs using AI.
30
-
31
- Args:
32
- logs: The deployment logs to analyze
33
- package_manager: Optional package manager context (uv, pip, poetry, npm, etc.)
34
- If provided, AI will target this manager's dependency file
35
- dependency_file: Optional dependency file context (pyproject.toml, requirements.txt, etc.)
36
- If provided, AI will suggest patches for this file
37
-
38
- Returns:
39
- DiagnosisResponse with diagnosis, suggestion, and optional patch
40
-
41
- Raises:
42
- XenfraAPIError: If the API request fails
43
- XenfraError: If parsing the response fails
44
- """
45
- try:
46
- # Build request payload
47
- payload = {"logs": logs}
48
- if package_manager:
49
- payload["package_manager"] = package_manager
50
- if dependency_file:
51
- payload["dependency_file"] = dependency_file
52
-
53
- response = self._client._request("POST", "/intelligence/diagnose", json=payload)
54
-
55
- logger.debug(f"IntelligenceManager.diagnose response: status={response.status_code}")
56
-
57
- # Safe JSON parsing
58
- data = safe_json_parse(response)
59
- return DiagnosisResponse(**data)
60
- except XenfraAPIError:
61
- raise
62
- except Exception as e:
63
- raise XenfraError(f"Failed to diagnose logs: {e}")
64
-
65
- def analyze_codebase(self, code_snippets: dict[str, str]) -> CodebaseAnalysisResponse:
66
- """
67
- Analyze codebase to detect framework, dependencies, and deployment config.
68
-
69
- Args:
70
- code_snippets: Dictionary of filename -> content
71
- e.g., {"main.py": "...", "requirements.txt": "..."}
72
-
73
- Returns:
74
- CodebaseAnalysisResponse with detected configuration
75
-
76
- Raises:
77
- XenfraAPIError: If the API request fails
78
- XenfraError: If parsing the response fails
79
- """
80
- try:
81
- response = self._client._request(
82
- "POST", "/intelligence/analyze-codebase", json={"code_snippets": code_snippets}
83
- )
84
-
85
- logger.debug(
86
- f"IntelligenceManager.analyze_codebase response: status={response.status_code}"
87
- )
88
-
89
- # Safe JSON parsing
90
- data = safe_json_parse(response)
91
- return CodebaseAnalysisResponse(**data)
92
- except XenfraAPIError:
93
- raise
94
- except Exception as e:
95
- raise XenfraError(f"Failed to analyze codebase: {e}")
1
+ """
2
+ Intelligence resource manager for Xenfra SDK.
3
+ Provides AI-powered deployment diagnosis and codebase analysis.
4
+ """
5
+
6
+ import logging
7
+
8
+ from ..exceptions import XenfraAPIError, XenfraError
9
+ from ..models import CodebaseAnalysisResponse, DiagnosisResponse
10
+ from ..utils import safe_json_parse
11
+ from .base import BaseManager
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class IntelligenceManager(BaseManager):
17
+ """
18
+ Manager for AI-powered intelligence operations.
19
+
20
+ Provides:
21
+ - Deployment failure diagnosis (Zen Nod)
22
+ - Codebase analysis for zero-config init (Zen Init)
23
+ """
24
+
25
+ def diagnose(
26
+ self, logs: str, package_manager: str | None = None, dependency_file: str | None = None
27
+ ) -> DiagnosisResponse:
28
+ """
29
+ Diagnose deployment failure from logs using AI.
30
+
31
+ Args:
32
+ logs: The deployment logs to analyze
33
+ package_manager: Optional package manager context (uv, pip, poetry, npm, etc.)
34
+ If provided, AI will target this manager's dependency file
35
+ dependency_file: Optional dependency file context (pyproject.toml, requirements.txt, etc.)
36
+ If provided, AI will suggest patches for this file
37
+
38
+ Returns:
39
+ DiagnosisResponse with diagnosis, suggestion, and optional patch
40
+
41
+ Raises:
42
+ XenfraAPIError: If the API request fails
43
+ XenfraError: If parsing the response fails
44
+ """
45
+ try:
46
+ # Build request payload
47
+ payload = {"logs": logs}
48
+ if package_manager:
49
+ payload["package_manager"] = package_manager
50
+ if dependency_file:
51
+ payload["dependency_file"] = dependency_file
52
+
53
+ response = self._client._request("POST", "/intelligence/diagnose", json=payload)
54
+
55
+ logger.debug(f"IntelligenceManager.diagnose response: status={response.status_code}")
56
+
57
+ # Safe JSON parsing
58
+ data = safe_json_parse(response)
59
+ return DiagnosisResponse(**data)
60
+ except XenfraAPIError:
61
+ raise
62
+ except Exception as e:
63
+ raise XenfraError(f"Failed to diagnose logs: {e}")
64
+
65
+ def analyze_codebase(self, code_snippets: dict[str, str]) -> CodebaseAnalysisResponse:
66
+ """
67
+ Analyze codebase to detect framework, dependencies, and deployment config.
68
+
69
+ Args:
70
+ code_snippets: Dictionary of filename -> content
71
+ e.g., {"main.py": "...", "requirements.txt": "..."}
72
+
73
+ Returns:
74
+ CodebaseAnalysisResponse with detected configuration
75
+
76
+ Raises:
77
+ XenfraAPIError: If the API request fails
78
+ XenfraError: If parsing the response fails
79
+ """
80
+ try:
81
+ response = self._client._request(
82
+ "POST", "/intelligence/analyze-codebase", json={"code_snippets": code_snippets}
83
+ )
84
+
85
+ logger.debug(
86
+ f"IntelligenceManager.analyze_codebase response: status={response.status_code}"
87
+ )
88
+
89
+ # Safe JSON parsing
90
+ data = safe_json_parse(response)
91
+ return CodebaseAnalysisResponse(**data)
92
+ except XenfraAPIError:
93
+ raise
94
+ except Exception as e:
95
+ raise XenfraError(f"Failed to analyze codebase: {e}")
xenfra_sdk/security.py CHANGED
@@ -1,41 +1,41 @@
1
- # src/xenfra_sdk/security.py
2
- """
3
- Security utilities for the Xenfra SDK.
4
- Provides token encryption/decryption for storing OAuth credentials.
5
- """
6
-
7
- import os
8
- from typing import Optional
9
-
10
- from cryptography.fernet import Fernet
11
-
12
- # --- Configuration from Environment ---
13
- # These should be set in the service's environment
14
- ENCRYPTION_KEY = os.getenv("ENCRYPTION_KEY", "")
15
-
16
-
17
- def _get_fernet() -> Optional[Fernet]:
18
- """Get Fernet instance for encryption/decryption."""
19
- if not ENCRYPTION_KEY:
20
- return None
21
- try:
22
- return Fernet(ENCRYPTION_KEY.encode())
23
- except Exception:
24
- return None
25
-
26
-
27
- # --- Token Encryption ---
28
- def encrypt_token(token: str) -> str:
29
- """Encrypts a token using Fernet symmetric encryption."""
30
- fernet = _get_fernet()
31
- if fernet is None:
32
- raise ValueError("ENCRYPTION_KEY environment variable is not set or invalid")
33
- return fernet.encrypt(token.encode()).decode()
34
-
35
-
36
- def decrypt_token(encrypted_token: str) -> str:
37
- """Decrypts a token."""
38
- fernet = _get_fernet()
39
- if fernet is None:
40
- raise ValueError("ENCRYPTION_KEY environment variable is not set or invalid")
41
- return fernet.decrypt(encrypted_token.encode()).decode()
1
+ # src/xenfra_sdk/security.py
2
+ """
3
+ Security utilities for the Xenfra SDK.
4
+ Provides token encryption/decryption for storing OAuth credentials.
5
+ """
6
+
7
+ import os
8
+ from typing import Optional
9
+
10
+ from cryptography.fernet import Fernet
11
+
12
+ # --- Configuration from Environment ---
13
+ # These should be set in the service's environment
14
+ ENCRYPTION_KEY = os.getenv("ENCRYPTION_KEY", "")
15
+
16
+
17
+ def _get_fernet() -> Optional[Fernet]:
18
+ """Get Fernet instance for encryption/decryption."""
19
+ if not ENCRYPTION_KEY:
20
+ return None
21
+ try:
22
+ return Fernet(ENCRYPTION_KEY.encode())
23
+ except Exception:
24
+ return None
25
+
26
+
27
+ # --- Token Encryption ---
28
+ def encrypt_token(token: str) -> str:
29
+ """Encrypts a token using Fernet symmetric encryption."""
30
+ fernet = _get_fernet()
31
+ if fernet is None:
32
+ raise ValueError("ENCRYPTION_KEY environment variable is not set or invalid")
33
+ return fernet.encrypt(token.encode()).decode()
34
+
35
+
36
+ def decrypt_token(encrypted_token: str) -> str:
37
+ """Decrypts a token."""
38
+ fernet = _get_fernet()
39
+ if fernet is None:
40
+ raise ValueError("ENCRYPTION_KEY environment variable is not set or invalid")
41
+ return fernet.decrypt(encrypted_token.encode()).decode()
@@ -1,25 +1,25 @@
1
- # Dockerfile template for Python web applications
2
- FROM {{ python_version | default('python:3.11-slim') }}
3
-
4
- WORKDIR /app
5
-
6
- # Install uv, our preferred package manager
7
- RUN apt-get update && apt-get install -y curl && \
8
- curl -LsSf https://astral.sh/uv/install.sh | sh && \
9
- apt-get remove -y curl && \
10
- apt-get clean && \
11
- rm -rf /var/lib/apt/lists/*
12
-
13
- COPY requirements.txt .
14
-
15
- # Install dependencies
16
- RUN /root/.cargo/bin/uv pip install --system --no-cache -r requirements.txt
17
-
18
- COPY . .
19
-
20
- # Expose the application port
21
- EXPOSE {{ port | default(8000) }}
22
-
23
- # The command to run the application will be in docker-compose.yml
24
- # This allows for more flexibility
25
-
1
+ # Dockerfile template for Python web applications
2
+ FROM {{ python_version | default('python:3.11-slim') }}
3
+
4
+ WORKDIR /app
5
+
6
+ # Install uv, our preferred package manager
7
+ RUN apt-get update && apt-get install -y curl && \
8
+ curl -LsSf https://astral.sh/uv/install.sh | sh && \
9
+ apt-get remove -y curl && \
10
+ apt-get clean && \
11
+ rm -rf /var/lib/apt/lists/*
12
+
13
+ COPY requirements.txt .
14
+
15
+ # Install dependencies
16
+ RUN /root/.cargo/bin/uv pip install --system --no-cache -r requirements.txt
17
+
18
+ COPY . .
19
+
20
+ # Expose the application port
21
+ EXPOSE {{ port | default(8000) }}
22
+
23
+ # The command to run the application will be in docker-compose.yml
24
+ # This allows for more flexibility
25
+
@@ -1,68 +1,68 @@
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
- # --- AGGRESSIVE FIX: KILL BACKGROUND UPDATES ---
15
- echo "⚔️ [0/6] Stopping Background Updates..." >> $LOG
16
- systemctl stop unattended-upgrades.service || true
17
- systemctl stop apt-daily.service || true
18
- systemctl stop apt-daily-upgrade.service || true
19
- systemctl kill --kill-who=all apt-daily.service || true
20
- systemctl kill --kill-who=all apt-daily-upgrade.service || true
21
-
22
- # Force remove locks if they exist
23
- rm -f /var/lib/dpkg/lock*
24
- rm -f /var/lib/apt/lists/lock
25
- rm -f /var/cache/apt/archives/lock
26
- dpkg --configure -a || true
27
- # -----------------------------------------------
28
-
29
- # 1. System Updates
30
- echo "🔄 [1/5] Refreshing Package Lists..." >> $LOG
31
- apt-get update
32
- apt-get install -y python3-pip git curl
33
-
34
- # 2. Install Docker & Compose
35
- echo "🐳 [2/5] Installing Docker..." >> $LOG
36
- apt-get install -y docker.io || (curl -fsSL https://get.docker.com | sh)
37
- echo "🎶 [3/5] Installing Docker Compose..." >> $LOG
38
- apt-get install -y docker-compose-v2
39
-
40
- # --- DOCKERIZED DEPLOYMENT ---
41
- echo "📦 [4/5] Installing Caddy..." >> $LOG
42
- apt-get install -y debian-keyring debian-archive-keyring apt-transport-https
43
- curl -LsSf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
44
- curl -LsSf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
45
- apt-get update
46
- apt-get install -y caddy
47
-
48
- {% if domain %}
49
- # Dynamically generate Caddyfile content
50
- echo "🔒 Writing Caddyfile for {{ domain }}..." >> $LOG
51
- cat << EOF > /etc/caddy/Caddyfile
52
- {{ domain }}:80, {{ domain }}:443 {
53
- reverse_proxy localhost:{{ port | default(8000) }}
54
- tls {{ email }}
55
- }
56
- EOF
57
- {% endif %}
58
-
59
- {% if domain %}
60
- echo "🚀 [5/5] Starting Caddy..." >> $LOG
61
- systemctl restart caddy
62
- {% else %}
63
- echo "✅ [5/5] Skipping Caddy start (no domain specified)." >> $LOG
64
- {% endif %}
65
-
66
- # Finish
67
- echo "✅ SETUP SCRIPT COMPLETE" >> $LOG
68
- touch /root/setup_complete
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
+ # --- AGGRESSIVE FIX: KILL BACKGROUND UPDATES ---
15
+ echo "⚔️ [0/6] Stopping Background Updates..." >> $LOG
16
+ systemctl stop unattended-upgrades.service || true
17
+ systemctl stop apt-daily.service || true
18
+ systemctl stop apt-daily-upgrade.service || true
19
+ systemctl kill --kill-who=all apt-daily.service || true
20
+ systemctl kill --kill-who=all apt-daily-upgrade.service || true
21
+
22
+ # Force remove locks if they exist
23
+ rm -f /var/lib/dpkg/lock*
24
+ rm -f /var/lib/apt/lists/lock
25
+ rm -f /var/cache/apt/archives/lock
26
+ dpkg --configure -a || true
27
+ # -----------------------------------------------
28
+
29
+ # 1. System Updates
30
+ echo "🔄 [1/5] Refreshing Package Lists..." >> $LOG
31
+ apt-get update
32
+ apt-get install -y python3-pip git curl
33
+
34
+ # 2. Install Docker & Compose
35
+ echo "🐳 [2/5] Installing Docker..." >> $LOG
36
+ apt-get install -y docker.io || (curl -fsSL https://get.docker.com | sh)
37
+ echo "🎶 [3/5] Installing Docker Compose..." >> $LOG
38
+ apt-get install -y docker-compose-v2
39
+
40
+ # --- DOCKERIZED DEPLOYMENT ---
41
+ echo "📦 [4/5] Installing Caddy..." >> $LOG
42
+ apt-get install -y debian-keyring debian-archive-keyring apt-transport-https
43
+ curl -LsSf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
44
+ curl -LsSf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
45
+ apt-get update
46
+ apt-get install -y caddy
47
+
48
+ {% if domain %}
49
+ # Dynamically generate Caddyfile content
50
+ echo "🔒 Writing Caddyfile for {{ domain }}..." >> $LOG
51
+ cat << EOF > /etc/caddy/Caddyfile
52
+ {{ domain }}:80, {{ domain }}:443 {
53
+ reverse_proxy localhost:{{ port | default(8000) }}
54
+ tls {{ email }}
55
+ }
56
+ EOF
57
+ {% endif %}
58
+
59
+ {% if domain %}
60
+ echo "🚀 [5/5] Starting Caddy..." >> $LOG
61
+ systemctl restart caddy
62
+ {% else %}
63
+ echo "✅ [5/5] Skipping Caddy start (no domain specified)." >> $LOG
64
+ {% endif %}
65
+
66
+ # Finish
67
+ echo "✅ SETUP SCRIPT COMPLETE" >> $LOG
68
+ touch /root/setup_complete
@@ -1,33 +1,33 @@
1
- # docker-compose.yml template
2
- version: '3.8'
3
-
4
- services:
5
- app:
6
- build: .
7
- ports:
8
- - "{{ port | default(8000) }}:{{ port | default(8000) }}"
9
- volumes:
10
- - .:/app
11
- command: {{ command }}
12
- {% if database == 'postgres' %}
13
- depends_on:
14
- - db
15
- environment:
16
- - DATABASE_URL=postgresql://{{ db_user | default('user') }}:{{ db_password | default('password') }}@db:5432/{{ db_name | default('appdb') }}
17
- {% endif %}
18
-
19
- {% if database == 'postgres' %}
20
- db:
21
- image: postgres:15-alpine
22
- volumes:
23
- - postgres_data:/var/lib/postgresql/data/
24
- environment:
25
- - POSTGRES_USER={{ db_user | default('user') }}
26
- - POSTGRES_PASSWORD={{ db_password | default('password') }}
27
- - POSTGRES_DB={{ db_name | default('appdb') }}
28
- {% endif %}
29
-
30
- volumes:
31
- {% if database == 'postgres' %}
32
- postgres_data:
33
- {% endif %}
1
+ # docker-compose.yml template
2
+ version: '3.8'
3
+
4
+ services:
5
+ app:
6
+ build: .
7
+ ports:
8
+ - "{{ port | default(8000) }}:{{ port | default(8000) }}"
9
+ volumes:
10
+ - .:/app
11
+ command: {{ command }}
12
+ {% if database == 'postgres' %}
13
+ depends_on:
14
+ - db
15
+ environment:
16
+ - DATABASE_URL=postgresql://{{ db_user | default('user') }}:{{ db_password | default('password') }}@db:5432/{{ db_name | default('appdb') }}
17
+ {% endif %}
18
+
19
+ {% if database == 'postgres' %}
20
+ db:
21
+ image: postgres:15-alpine
22
+ volumes:
23
+ - postgres_data:/var/lib/postgresql/data/
24
+ environment:
25
+ - POSTGRES_USER={{ db_user | default('user') }}
26
+ - POSTGRES_PASSWORD={{ db_password | default('password') }}
27
+ - POSTGRES_DB={{ db_name | default('appdb') }}
28
+ {% endif %}
29
+
30
+ volumes:
31
+ {% if database == 'postgres' %}
32
+ postgres_data:
33
+ {% endif %}