parad 1.0.0__tar.gz

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.
@@ -0,0 +1,5 @@
1
+ include LICENSE
2
+ include README.md
3
+ include pyproject.toml
4
+ recursive-include parad *.py
5
+ recursive-include tests *.py
parad-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.1
2
+ Name: parad
3
+ Version: 1.0.0
4
+ Summary: CLI client for Nexuss Bash remote execution API
5
+ Home-page: https://github.com/nexuss0781/Nexuss-Bash
6
+ Author: Nexuss
7
+ Author-email: Nexuss <nexuss@proton.me>
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/nexuss0781/Nexuss-Bash
10
+ Project-URL: Bug Reports, https://github.com/nexuss0781/Nexuss-Bash/issues
11
+ Project-URL: Source, https://github.com/nexuss0781/Nexuss-Bash
12
+ Keywords: cli,bash,remote,execution,api,nexuss,parad
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: System Administrators
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.8
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Topic :: System :: Systems Administration
25
+ Classifier: Topic :: Software Development :: Build Tools
26
+ Classifier: Topic :: Utilities
27
+ Requires-Python: >=3.8
28
+ Description-Content-Type: text/markdown
29
+ Provides-Extra: dev
30
+
31
+ # parad
32
+
33
+ CLI client for the **Nexuss Bash** remote execution API. Run shell commands on a remote server directly from your terminal.
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install parad
39
+ ```
40
+
41
+ Or from source:
42
+
43
+ ```bash
44
+ git clone https://github.com/nexuss0781/Nexuss-Bash
45
+ cd Nexuss-Bash/cli
46
+ pip install -e .
47
+ ```
48
+
49
+ ## Quick Start
50
+
51
+ ```bash
52
+ # Authenticate
53
+ parad auth YOUR_API_TOKEN
54
+
55
+ # Run commands
56
+ parad run "echo hello" "whoami" "ls /workspace"
57
+
58
+ # Execute a YAML file
59
+ parad execute runbook.yaml
60
+
61
+ # Check status
62
+ parad status
63
+ ```
64
+
65
+ ## Commands
66
+
67
+ | Command | Description |
68
+ |---------|-------------|
69
+ | `parad auth <token>` | Save authentication token |
70
+ | `parad run <commands...>` | Run shell commands sequentially |
71
+ | `parad execute <yaml_file>` | Execute commands from a YAML file |
72
+ | `parad status` | Show connection and token info |
73
+ | `parad history` | List past runs |
74
+ | `parad health` | Quick health check |
75
+ | `parad sessions` | List active sessions |
76
+ | `parad packages list` | List installed packages |
77
+ | `parad packages install <name>` | Install a package |
78
+ | `parad config` | Show or set API URL |
79
+ | `parad logout` | Remove saved token |
80
+
81
+ ## YAML File Format
82
+
83
+ ### Simple format
84
+
85
+ ```yaml
86
+ commands:
87
+ - "echo hello"
88
+ - "whoami"
89
+ - "ls -la /workspace"
90
+ ```
91
+
92
+ ### Detailed format
93
+
94
+ ```yaml
95
+ commands:
96
+ - name: "Print hello"
97
+ command: "echo hello"
98
+ timeout: 30
99
+ stop_on_fail: true
100
+ - name: "List files"
101
+ command: "ls -la"
102
+ timeout: 15
103
+ ```
104
+
105
+ ## Configuration
106
+
107
+ Config is stored at `~/.parad/config.json`.
108
+
109
+ ```bash
110
+ # Set custom API URL
111
+ parad config set https://my-server.example.com
112
+
113
+ # Show current config
114
+ parad config
115
+ ```
116
+
117
+ ## Environment
118
+
119
+ - Python 3.8+
120
+ - Works on Linux, macOS, Windows
121
+
122
+ ## License
123
+
124
+ MIT
parad-1.0.0/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # parad
2
+
3
+ CLI client for the **Nexuss Bash** remote execution API. Run shell commands on a remote server directly from your terminal.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install parad
9
+ ```
10
+
11
+ Or from source:
12
+
13
+ ```bash
14
+ git clone https://github.com/nexuss0781/Nexuss-Bash
15
+ cd Nexuss-Bash/cli
16
+ pip install -e .
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ # Authenticate
23
+ parad auth YOUR_API_TOKEN
24
+
25
+ # Run commands
26
+ parad run "echo hello" "whoami" "ls /workspace"
27
+
28
+ # Execute a YAML file
29
+ parad execute runbook.yaml
30
+
31
+ # Check status
32
+ parad status
33
+ ```
34
+
35
+ ## Commands
36
+
37
+ | Command | Description |
38
+ |---------|-------------|
39
+ | `parad auth <token>` | Save authentication token |
40
+ | `parad run <commands...>` | Run shell commands sequentially |
41
+ | `parad execute <yaml_file>` | Execute commands from a YAML file |
42
+ | `parad status` | Show connection and token info |
43
+ | `parad history` | List past runs |
44
+ | `parad health` | Quick health check |
45
+ | `parad sessions` | List active sessions |
46
+ | `parad packages list` | List installed packages |
47
+ | `parad packages install <name>` | Install a package |
48
+ | `parad config` | Show or set API URL |
49
+ | `parad logout` | Remove saved token |
50
+
51
+ ## YAML File Format
52
+
53
+ ### Simple format
54
+
55
+ ```yaml
56
+ commands:
57
+ - "echo hello"
58
+ - "whoami"
59
+ - "ls -la /workspace"
60
+ ```
61
+
62
+ ### Detailed format
63
+
64
+ ```yaml
65
+ commands:
66
+ - name: "Print hello"
67
+ command: "echo hello"
68
+ timeout: 30
69
+ stop_on_fail: true
70
+ - name: "List files"
71
+ command: "ls -la"
72
+ timeout: 15
73
+ ```
74
+
75
+ ## Configuration
76
+
77
+ Config is stored at `~/.parad/config.json`.
78
+
79
+ ```bash
80
+ # Set custom API URL
81
+ parad config set https://my-server.example.com
82
+
83
+ # Show current config
84
+ parad config
85
+ ```
86
+
87
+ ## Environment
88
+
89
+ - Python 3.8+
90
+ - Works on Linux, macOS, Windows
91
+
92
+ ## License
93
+
94
+ MIT
@@ -0,0 +1,4 @@
1
+ """parad - CLI client for Nexuss Bash remote execution API."""
2
+
3
+ __version__ = "1.0.0"
4
+ __app_name__ = "parad"
@@ -0,0 +1,6 @@
1
+ """Allow running parad as a module: python -m parad."""
2
+
3
+ from parad.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -0,0 +1,149 @@
1
+ """API client for Nexuss Bash."""
2
+
3
+ import json
4
+ from typing import Optional, Any
5
+
6
+ import requests
7
+ from requests.exceptions import ConnectionError, HTTPError, RequestException, Timeout
8
+
9
+ from parad.config import get_api_url, get_token
10
+
11
+
12
+ class APIError(Exception):
13
+ def __init__(self, message: str, status_code: Optional[int] = None):
14
+ self.message = message
15
+ self.status_code = status_code
16
+ super().__init__(self.message)
17
+
18
+
19
+ class AuthError(APIError):
20
+ pass
21
+
22
+
23
+ class ConnectionError_(APIError):
24
+ pass
25
+
26
+
27
+ def _build_headers() -> dict:
28
+ headers = {"Content-Type": "application/json"}
29
+ token = get_token()
30
+ if token:
31
+ headers["Authorization"] = f"Bearer {token}"
32
+ return headers
33
+
34
+
35
+ def _build_url(path: str) -> str:
36
+ base = get_api_url().rstrip("/")
37
+ path = path.lstrip("/")
38
+ return f"{base}/{path}"
39
+
40
+
41
+ def api_get(path: str) -> dict:
42
+ url = _build_url(path)
43
+ try:
44
+ resp = requests.get(url, headers=_build_headers(), timeout=30)
45
+ resp.raise_for_status()
46
+ return resp.json()
47
+ except HTTPError as e:
48
+ status = e.response.status_code if e.response is not None else None
49
+ if status == 401:
50
+ raise AuthError("Authentication failed. Run: parad auth <token>", status)
51
+ if status == 404:
52
+ raise APIError(f"Not found: {path}", status)
53
+ raise APIError(f"HTTP {status}: {e}", status)
54
+ except ConnectionError:
55
+ raise ConnectionError_(f"Cannot connect to {url}. Check your network and API URL.")
56
+ except Timeout:
57
+ raise APIError(f"Request timed out: {url}")
58
+ except RequestException as e:
59
+ raise APIError(f"Request failed: {e}")
60
+ except json.JSONDecodeError:
61
+ raise APIError("Invalid JSON response from server")
62
+
63
+
64
+ def api_post(path: str, data: Optional[dict] = None) -> dict:
65
+ url = _build_url(path)
66
+ try:
67
+ resp = requests.post(url, headers=_build_headers(), json=data or {}, timeout=30)
68
+ resp.raise_for_status()
69
+ return resp.json()
70
+ except HTTPError as e:
71
+ status = e.response.status_code if e.response is not None else None
72
+ if status == 401:
73
+ raise AuthError("Authentication failed. Run: parad auth <token>", status)
74
+ if status == 404:
75
+ raise APIError(f"Not found: {path}", status)
76
+ body = ""
77
+ if e.response is not None:
78
+ try:
79
+ body = e.response.json().get("detail", e.response.text)
80
+ except Exception:
81
+ body = e.response.text
82
+ raise APIError(f"HTTP {status}: {body}", status)
83
+ except ConnectionError:
84
+ raise ConnectionError_(f"Cannot connect to {url}. Check your network and API URL.")
85
+ except Timeout:
86
+ raise APIError(f"Request timed out: {url}")
87
+ except RequestException as e:
88
+ raise APIError(f"Request failed: {e}")
89
+ except json.JSONDecodeError:
90
+ raise APIError("Invalid JSON response from server")
91
+
92
+
93
+ def api_post_file(path: str, file_path: str) -> dict:
94
+ url = _build_url(path)
95
+ token = get_token()
96
+ headers = {}
97
+ if token:
98
+ headers["Authorization"] = f"Bearer {token}"
99
+ try:
100
+ with open(file_path, "rb") as f:
101
+ files = {"file": (file_path.split("/")[-1], f)}
102
+ resp = requests.post(url, headers=headers, files=files, timeout=60)
103
+ resp.raise_for_status()
104
+ return resp.json()
105
+ except HTTPError as e:
106
+ status = e.response.status_code if e.response is not None else None
107
+ if status == 401:
108
+ raise AuthError("Authentication failed. Run: parad auth <token>", status)
109
+ raise APIError(f"HTTP {status}: {e}", status)
110
+ except ConnectionError:
111
+ raise ConnectionError_(f"Cannot connect to {url}. Check your network and API URL.")
112
+ except Timeout:
113
+ raise APIError(f"Request timed out: {url}")
114
+ except RequestException as e:
115
+ raise APIError(f"Request failed: {e}")
116
+ except FileNotFoundError:
117
+ raise APIError(f"File not found: {file_path}")
118
+ except json.JSONDecodeError:
119
+ raise APIError("Invalid JSON response from server")
120
+
121
+
122
+ def api_delete(path: str) -> dict:
123
+ url = _build_url(path)
124
+ try:
125
+ resp = requests.delete(url, headers=_build_headers(), timeout=30)
126
+ resp.raise_for_status()
127
+ return resp.json()
128
+ except HTTPError as e:
129
+ status = e.response.status_code if e.response is not None else None
130
+ if status == 401:
131
+ raise AuthError("Authentication failed. Run: parad auth <token>", status)
132
+ raise APIError(f"HTTP {status}: {e}", status)
133
+ except ConnectionError:
134
+ raise ConnectionError_(f"Cannot connect to {url}. Check your network and API URL.")
135
+ except Timeout:
136
+ raise APIError(f"Request timed out: {url}")
137
+ except RequestException as e:
138
+ raise APIError(f"Request failed: {e}")
139
+ except json.JSONDecodeError:
140
+ raise APIError("Invalid JSON response from server")
141
+
142
+
143
+ def test_connection() -> bool:
144
+ try:
145
+ url = _build_url("/health")
146
+ resp = requests.get(url, timeout=10)
147
+ return resp.status_code == 200
148
+ except Exception:
149
+ return False