mobox-cli 0.1.0__tar.gz → 0.1.2__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.
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/.gitignore +69 -69
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/PKG-INFO +2 -2
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/pyproject.toml +21 -21
- mobox_cli-0.1.2/src/mobox/__init__.py +1 -0
- mobox_cli-0.1.2/src/mobox/appserver_client.py +195 -0
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/auth.py +254 -254
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/client.py +98 -98
- mobox_cli-0.1.2/src/mobox/commands/appserver.py +182 -0
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/commands/deploy.py +143 -125
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/commands/local.py +82 -82
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/commands/manage.py +188 -188
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/commands/ops.py +125 -125
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/config.py +82 -82
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/local/analyze_volumes.py +483 -483
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/local/config_utils.py +631 -631
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/local/detect_framework.py +1406 -1406
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/local/detect_project.py +388 -388
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/local/pack_project.py +543 -543
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/main.py +109 -103
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/utils.py +52 -52
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/tests/test_auth_i18n.py +138 -138
- mobox_cli-0.1.2/tests/test_deploy_validation.py +29 -0
- mobox_cli-0.1.0/src/mobox/__init__.py +0 -1
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/commands/__init__.py +0 -0
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/local/__init__.py +0 -0
- {mobox_cli-0.1.0 → mobox_cli-0.1.2}/tests/__init__.py +0 -0
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
# Docker persistent volumes
|
|
2
|
-
volumes/
|
|
3
|
-
|
|
4
|
-
# Environment
|
|
5
|
-
.env
|
|
6
|
-
.env.local
|
|
7
|
-
.env.*.local
|
|
8
|
-
|
|
9
|
-
# Python
|
|
10
|
-
__pycache__/
|
|
11
|
-
*.pyc
|
|
12
|
-
venv/
|
|
13
|
-
|
|
14
|
-
# Node
|
|
15
|
-
**/node_modules/
|
|
16
|
-
|
|
17
|
-
# Build outputs
|
|
18
|
-
**/.next/
|
|
19
|
-
**/out/
|
|
20
|
-
**/dist/
|
|
21
|
-
**/build/
|
|
22
|
-
|
|
23
|
-
# Logs
|
|
24
|
-
*.log
|
|
25
|
-
logs/
|
|
26
|
-
|
|
27
|
-
# OS
|
|
28
|
-
.DS_Store
|
|
29
|
-
|
|
30
|
-
# Claude
|
|
31
|
-
**/.claude/
|
|
32
|
-
**/CLAUDE.md
|
|
33
|
-
|
|
34
|
-
# Python venv
|
|
35
|
-
*/.venv/
|
|
36
|
-
|
|
37
|
-
# Runtime files
|
|
38
|
-
*.pid
|
|
39
|
-
|
|
40
|
-
# Database
|
|
41
|
-
data/*.db
|
|
42
|
-
data/*.db-journal
|
|
43
|
-
|
|
44
|
-
# Tests (optional)
|
|
45
|
-
orchestrator/tests/
|
|
46
|
-
|
|
47
|
-
# Uploads and backups
|
|
48
|
-
uploads/
|
|
49
|
-
backups/
|
|
50
|
-
.ace-tool/
|
|
51
|
-
|
|
52
|
-
# Business confidential
|
|
53
|
-
BUSINESS_PLAN.md
|
|
54
|
-
|
|
55
|
-
app-deploy.json
|
|
56
|
-
|
|
57
|
-
# RSA push
|
|
58
|
-
rsa_push/
|
|
59
|
-
.superpowers/
|
|
60
|
-
.worktrees/
|
|
61
|
-
|
|
62
|
-
# CI runtime
|
|
63
|
-
ci/__pycache__/
|
|
64
|
-
ci/state.json
|
|
65
|
-
|
|
66
|
-
# Configuration files (may contain sensitive data)
|
|
67
|
-
config/*.yaml
|
|
68
|
-
config/.secret
|
|
69
|
-
orchestrator/config/*.yaml
|
|
1
|
+
# Docker persistent volumes
|
|
2
|
+
volumes/
|
|
3
|
+
|
|
4
|
+
# Environment
|
|
5
|
+
.env
|
|
6
|
+
.env.local
|
|
7
|
+
.env.*.local
|
|
8
|
+
|
|
9
|
+
# Python
|
|
10
|
+
__pycache__/
|
|
11
|
+
*.pyc
|
|
12
|
+
venv/
|
|
13
|
+
|
|
14
|
+
# Node
|
|
15
|
+
**/node_modules/
|
|
16
|
+
|
|
17
|
+
# Build outputs
|
|
18
|
+
**/.next/
|
|
19
|
+
**/out/
|
|
20
|
+
**/dist/
|
|
21
|
+
**/build/
|
|
22
|
+
|
|
23
|
+
# Logs
|
|
24
|
+
*.log
|
|
25
|
+
logs/
|
|
26
|
+
|
|
27
|
+
# OS
|
|
28
|
+
.DS_Store
|
|
29
|
+
|
|
30
|
+
# Claude
|
|
31
|
+
**/.claude/
|
|
32
|
+
**/CLAUDE.md
|
|
33
|
+
|
|
34
|
+
# Python venv
|
|
35
|
+
*/.venv/
|
|
36
|
+
|
|
37
|
+
# Runtime files
|
|
38
|
+
*.pid
|
|
39
|
+
|
|
40
|
+
# Database
|
|
41
|
+
data/*.db
|
|
42
|
+
data/*.db-journal
|
|
43
|
+
|
|
44
|
+
# Tests (optional)
|
|
45
|
+
orchestrator/tests/
|
|
46
|
+
|
|
47
|
+
# Uploads and backups
|
|
48
|
+
uploads/
|
|
49
|
+
backups/
|
|
50
|
+
.ace-tool/
|
|
51
|
+
|
|
52
|
+
# Business confidential
|
|
53
|
+
BUSINESS_PLAN.md
|
|
54
|
+
|
|
55
|
+
app-deploy.json
|
|
56
|
+
|
|
57
|
+
# RSA push
|
|
58
|
+
rsa_push/
|
|
59
|
+
.superpowers/
|
|
60
|
+
.worktrees/
|
|
61
|
+
|
|
62
|
+
# CI runtime
|
|
63
|
+
ci/__pycache__/
|
|
64
|
+
ci/state.json
|
|
65
|
+
|
|
66
|
+
# Configuration files (may contain sensitive data)
|
|
67
|
+
config/*.yaml
|
|
68
|
+
config/.secret
|
|
69
|
+
orchestrator/config/*.yaml
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["hatchling"]
|
|
3
|
-
build-backend = "hatchling.build"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "mobox-cli"
|
|
7
|
-
version = "0.1.
|
|
8
|
-
description = "Mobox deployment CLI - detect, pack, deploy and manage applications"
|
|
9
|
-
requires-python = ">=3.10"
|
|
10
|
-
dependencies = [
|
|
11
|
-
"typer>=0.12",
|
|
12
|
-
"rich>=13.0",
|
|
13
|
-
"httpx>=0.27",
|
|
14
|
-
"mcp>=1.0",
|
|
15
|
-
]
|
|
16
|
-
|
|
17
|
-
[project.scripts]
|
|
18
|
-
mobox = "mobox.main:app"
|
|
19
|
-
|
|
20
|
-
[tool.hatch.build.targets.wheel]
|
|
21
|
-
packages = ["src/mobox"]
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mobox-cli"
|
|
7
|
+
version = "0.1.2"
|
|
8
|
+
description = "Mobox deployment CLI - detect, pack, deploy and manage applications"
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"typer>=0.12",
|
|
12
|
+
"rich>=13.0",
|
|
13
|
+
"httpx>=0.27",
|
|
14
|
+
"mcp>=1.0",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.scripts]
|
|
18
|
+
mobox = "mobox.main:app"
|
|
19
|
+
|
|
20
|
+
[tool.hatch.build.targets.wheel]
|
|
21
|
+
packages = ["src/mobox"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.2"
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""App Server Client - HTTP communication with EVOL App Server"""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
from mobox import utils
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AppServerClient:
|
|
11
|
+
"""HTTP client for EVOL App Server internal APIs"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, base_url: str, internal_token: str):
|
|
14
|
+
self.base_url = base_url.rstrip("/")
|
|
15
|
+
self.internal_token = internal_token
|
|
16
|
+
self.timeout = httpx.Timeout(30.0)
|
|
17
|
+
|
|
18
|
+
def _get_headers(self) -> dict:
|
|
19
|
+
"""Get common headers with authorization"""
|
|
20
|
+
return {
|
|
21
|
+
"Authorization": f"Bearer {self.internal_token}",
|
|
22
|
+
"Content-Type": "application/json",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async def health_check(self) -> dict:
|
|
26
|
+
"""Check App Server health status"""
|
|
27
|
+
try:
|
|
28
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
29
|
+
resp = await client.get(f"{self.base_url}/health")
|
|
30
|
+
resp.raise_for_status()
|
|
31
|
+
return {"success": True, "data": resp.json()}
|
|
32
|
+
except Exception as e:
|
|
33
|
+
return {"success": False, "error": str(e)}
|
|
34
|
+
|
|
35
|
+
async def report_install_status(
|
|
36
|
+
self,
|
|
37
|
+
install_session_id: str,
|
|
38
|
+
status: str,
|
|
39
|
+
host_name: Optional[str] = None,
|
|
40
|
+
platform: Optional[str] = None,
|
|
41
|
+
evolclaw_version: Optional[str] = None,
|
|
42
|
+
daemon_aid: Optional[str] = None,
|
|
43
|
+
mobox_trace_id: Optional[str] = None,
|
|
44
|
+
error_code: Optional[str] = None,
|
|
45
|
+
error_message: Optional[str] = None,
|
|
46
|
+
) -> dict:
|
|
47
|
+
"""
|
|
48
|
+
Report installation/initialization status to App Server
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
install_session_id: Installation session ID from App Server (his_xxx)
|
|
52
|
+
status: One of: installing, initialized, bind_ready, bound, failed
|
|
53
|
+
host_name: Computer hostname
|
|
54
|
+
platform: windows/macos/linux
|
|
55
|
+
evolclaw_version: EvolClaw version
|
|
56
|
+
daemon_aid: EvolClaw Daemon AID (required for bind_ready status)
|
|
57
|
+
mobox_trace_id: MoBox trace ID for debugging
|
|
58
|
+
error_code: Error code when status is failed
|
|
59
|
+
error_message: Error message when status is failed
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
dict with success, host_id, and status
|
|
63
|
+
"""
|
|
64
|
+
payload = {
|
|
65
|
+
"install_session_id": install_session_id,
|
|
66
|
+
"status": status,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# Add optional fields
|
|
70
|
+
if host_name:
|
|
71
|
+
payload["host_name"] = host_name
|
|
72
|
+
if platform:
|
|
73
|
+
payload["platform"] = platform
|
|
74
|
+
if evolclaw_version:
|
|
75
|
+
payload["evolclaw_version"] = evolclaw_version
|
|
76
|
+
if daemon_aid:
|
|
77
|
+
payload["daemon_aid"] = daemon_aid
|
|
78
|
+
if mobox_trace_id:
|
|
79
|
+
payload["mobox_trace_id"] = mobox_trace_id
|
|
80
|
+
if error_code:
|
|
81
|
+
payload["error_code"] = error_code
|
|
82
|
+
if error_message:
|
|
83
|
+
payload["error_message"] = error_message
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
87
|
+
resp = await client.post(
|
|
88
|
+
f"{self.base_url}/internal/mobox/hosts/install/status",
|
|
89
|
+
json=payload,
|
|
90
|
+
headers=self._get_headers(),
|
|
91
|
+
)
|
|
92
|
+
resp.raise_for_status()
|
|
93
|
+
data = resp.json()
|
|
94
|
+
return {"success": True, "data": data}
|
|
95
|
+
except httpx.HTTPStatusError as e:
|
|
96
|
+
try:
|
|
97
|
+
error_detail = e.response.json().get("error", str(e))
|
|
98
|
+
except Exception:
|
|
99
|
+
error_detail = str(e)
|
|
100
|
+
return {"success": False, "error": error_detail, "status_code": e.response.status_code}
|
|
101
|
+
except Exception as e:
|
|
102
|
+
return {"success": False, "error": str(e)}
|
|
103
|
+
|
|
104
|
+
async def report_heartbeat(
|
|
105
|
+
self,
|
|
106
|
+
daemon_aid: str,
|
|
107
|
+
host_name: Optional[str] = None,
|
|
108
|
+
platform: Optional[str] = None,
|
|
109
|
+
evolclaw_version: Optional[str] = None,
|
|
110
|
+
capabilities: Optional[dict] = None,
|
|
111
|
+
agent_summary: Optional[dict] = None,
|
|
112
|
+
) -> dict:
|
|
113
|
+
"""
|
|
114
|
+
Report host heartbeat to App Server
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
daemon_aid: EvolClaw Daemon AID
|
|
118
|
+
host_name: Computer hostname
|
|
119
|
+
platform: windows/macos/linux
|
|
120
|
+
evolclaw_version: EvolClaw version
|
|
121
|
+
capabilities: Host capabilities dict (e.g., {"agent_create": true, "menu_protocol": true})
|
|
122
|
+
agent_summary: Agent count summary (e.g., {"total": 1, "running": 1})
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
dict with success, host_id, and last_seen_at
|
|
126
|
+
"""
|
|
127
|
+
payload = {"daemon_aid": daemon_aid}
|
|
128
|
+
|
|
129
|
+
# Add optional fields
|
|
130
|
+
if host_name:
|
|
131
|
+
payload["host_name"] = host_name
|
|
132
|
+
if platform:
|
|
133
|
+
payload["platform"] = platform
|
|
134
|
+
if evolclaw_version:
|
|
135
|
+
payload["evolclaw_version"] = evolclaw_version
|
|
136
|
+
if capabilities:
|
|
137
|
+
payload["capabilities"] = capabilities
|
|
138
|
+
if agent_summary:
|
|
139
|
+
payload["agent_summary"] = agent_summary
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
143
|
+
resp = await client.post(
|
|
144
|
+
f"{self.base_url}/internal/mobox/hosts/heartbeat",
|
|
145
|
+
json=payload,
|
|
146
|
+
headers=self._get_headers(),
|
|
147
|
+
)
|
|
148
|
+
resp.raise_for_status()
|
|
149
|
+
data = resp.json()
|
|
150
|
+
return {"success": True, "data": data}
|
|
151
|
+
except httpx.HTTPStatusError as e:
|
|
152
|
+
try:
|
|
153
|
+
error_detail = e.response.json().get("error", str(e))
|
|
154
|
+
except Exception:
|
|
155
|
+
error_detail = str(e)
|
|
156
|
+
return {"success": False, "error": error_detail, "status_code": e.response.status_code}
|
|
157
|
+
except Exception as e:
|
|
158
|
+
return {"success": False, "error": str(e)}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def get_appserver_client(
|
|
162
|
+
base_url: Optional[str] = None,
|
|
163
|
+
internal_token: Optional[str] = None,
|
|
164
|
+
) -> AppServerClient:
|
|
165
|
+
"""
|
|
166
|
+
Create AppServerClient with default or provided credentials
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
base_url: App Server base URL (default: https://app.evolai.cn)
|
|
170
|
+
internal_token: Internal token for authentication (default: from env or config)
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
AppServerClient instance
|
|
174
|
+
"""
|
|
175
|
+
import os
|
|
176
|
+
from mobox.config import get_config
|
|
177
|
+
|
|
178
|
+
if not base_url:
|
|
179
|
+
base_url = os.getenv(
|
|
180
|
+
"APP_SERVER_BASE_URL",
|
|
181
|
+
get_config("app_server_base_url", "https://app.evolai.cn")
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
if not internal_token:
|
|
185
|
+
internal_token = os.getenv(
|
|
186
|
+
"MOBOX_INTERNAL_TOKEN",
|
|
187
|
+
get_config("mobox_internal_token", "")
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
if not internal_token:
|
|
191
|
+
utils.error("MOBOX_INTERNAL_TOKEN not configured. Set via environment variable or config.")
|
|
192
|
+
import typer
|
|
193
|
+
raise typer.Exit(1)
|
|
194
|
+
|
|
195
|
+
return AppServerClient(base_url, internal_token)
|