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.
Files changed (26) hide show
  1. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/.gitignore +69 -69
  2. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/PKG-INFO +2 -2
  3. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/pyproject.toml +21 -21
  4. mobox_cli-0.1.2/src/mobox/__init__.py +1 -0
  5. mobox_cli-0.1.2/src/mobox/appserver_client.py +195 -0
  6. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/auth.py +254 -254
  7. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/client.py +98 -98
  8. mobox_cli-0.1.2/src/mobox/commands/appserver.py +182 -0
  9. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/commands/deploy.py +143 -125
  10. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/commands/local.py +82 -82
  11. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/commands/manage.py +188 -188
  12. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/commands/ops.py +125 -125
  13. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/config.py +82 -82
  14. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/local/analyze_volumes.py +483 -483
  15. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/local/config_utils.py +631 -631
  16. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/local/detect_framework.py +1406 -1406
  17. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/local/detect_project.py +388 -388
  18. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/local/pack_project.py +543 -543
  19. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/main.py +109 -103
  20. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/utils.py +52 -52
  21. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/tests/test_auth_i18n.py +138 -138
  22. mobox_cli-0.1.2/tests/test_deploy_validation.py +29 -0
  23. mobox_cli-0.1.0/src/mobox/__init__.py +0 -1
  24. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/commands/__init__.py +0 -0
  25. {mobox_cli-0.1.0 → mobox_cli-0.1.2}/src/mobox/local/__init__.py +0 -0
  26. {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,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: mobox-cli
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Mobox deployment CLI - detect, pack, deploy and manage applications
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: httpx>=0.27
@@ -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.0"
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)