huimei 0.1.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.
Files changed (43) hide show
  1. huimei-0.1.0/PKG-INFO +134 -0
  2. huimei-0.1.0/README.md +98 -0
  3. huimei-0.1.0/huimei.egg-info/PKG-INFO +134 -0
  4. huimei-0.1.0/huimei.egg-info/SOURCES.txt +41 -0
  5. huimei-0.1.0/huimei.egg-info/dependency_links.txt +1 -0
  6. huimei-0.1.0/huimei.egg-info/entry_points.txt +3 -0
  7. huimei-0.1.0/huimei.egg-info/requires.txt +14 -0
  8. huimei-0.1.0/huimei.egg-info/top_level.txt +1 -0
  9. huimei-0.1.0/huimei_cli/__init__.py +2 -0
  10. huimei-0.1.0/huimei_cli/api_client.py +105 -0
  11. huimei-0.1.0/huimei_cli/auth.py +72 -0
  12. huimei-0.1.0/huimei_cli/commands/__init__.py +1 -0
  13. huimei-0.1.0/huimei_cli/commands/account_cmd.py +106 -0
  14. huimei-0.1.0/huimei_cli/commands/auth_cmd.py +67 -0
  15. huimei-0.1.0/huimei_cli/commands/publish_cmd.py +119 -0
  16. huimei-0.1.0/huimei_cli/config.py +72 -0
  17. huimei-0.1.0/huimei_cli/engine/__init__.py +0 -0
  18. huimei-0.1.0/huimei_cli/engine/browser.py +83 -0
  19. huimei-0.1.0/huimei_cli/engine/output.py +55 -0
  20. huimei-0.1.0/huimei_cli/engine/router.py +72 -0
  21. huimei-0.1.0/huimei_cli/engine/session.py +111 -0
  22. huimei-0.1.0/huimei_cli/main.py +102 -0
  23. huimei-0.1.0/huimei_cli/mcp_server.py +150 -0
  24. huimei-0.1.0/huimei_cli/platforms/__init__.py +0 -0
  25. huimei-0.1.0/huimei_cli/platforms/registry/__init__.py +6 -0
  26. huimei-0.1.0/huimei_cli/platforms/registry/_template.py +122 -0
  27. huimei-0.1.0/huimei_cli/platforms/registry/baijiahao.py +37 -0
  28. huimei-0.1.0/huimei_cli/platforms/registry/bilibili.py +97 -0
  29. huimei-0.1.0/huimei_cli/platforms/registry/douyin.py +9 -0
  30. huimei-0.1.0/huimei_cli/platforms/registry/ks.py +25 -0
  31. huimei-0.1.0/huimei_cli/platforms/registry/sample.py +79 -0
  32. huimei-0.1.0/huimei_cli/platforms/registry/tencent.py +25 -0
  33. huimei-0.1.0/huimei_cli/platforms/registry/tk.py +25 -0
  34. huimei-0.1.0/huimei_cli/platforms/registry/toutiao.py +72 -0
  35. huimei-0.1.0/huimei_cli/platforms/registry/weibo.py +164 -0
  36. huimei-0.1.0/huimei_cli/platforms/registry/weixingongzhonghao.py +48 -0
  37. huimei-0.1.0/huimei_cli/platforms/registry/xhs.py +73 -0
  38. huimei-0.1.0/huimei_cli/platforms/registry/zhihu.py +25 -0
  39. huimei-0.1.0/pyproject.toml +57 -0
  40. huimei-0.1.0/setup.cfg +4 -0
  41. huimei-0.1.0/tests/test_cli.py +24 -0
  42. huimei-0.1.0/tests/test_core.py +126 -0
  43. huimei-0.1.0/tests/test_mcp.py +41 -0
huimei-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.4
2
+ Name: huimei
3
+ Version: 0.1.0
4
+ Summary: Multi-platform social media automation CLI — publish to Douyin, XHS, Bilibili, Weibo and 8+ platforms from your terminal
5
+ Author: HuiMei Team
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/huimei-engine/huimei-cli
8
+ Project-URL: Repository, https://codeup.aliyun.com/6832d8ec9c32f0e37238744f/huimei-cli
9
+ Keywords: social-media,automation,cli,douyin,bilibili,xiaohongshu,playwright,cross-posting,marketing
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Internet
20
+ Classifier: Topic :: Multimedia
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: typer>=0.12.0
24
+ Requires-Dist: httpx>=0.27.0
25
+ Requires-Dist: rich>=13.0.0
26
+ Requires-Dist: playwright>=1.40.0
27
+ Requires-Dist: pydantic>=2.0.0
28
+ Requires-Dist: pycryptodome>=3.20.0
29
+ Requires-Dist: keyring>=25.0.0
30
+ Requires-Dist: mcp>=1.0.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
33
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
34
+ Requires-Dist: build; extra == "dev"
35
+ Requires-Dist: twine; extra == "dev"
36
+
37
+ # 慧媒引擎 CLI (huimei)
38
+
39
+ 多平台社媒自动化发布工具 — 一个命令发布到抖音/快手/B站/小红书/微博等11个平台。
40
+
41
+ ## 安装
42
+
43
+ ### 方式1: pip (推荐)
44
+ ```bash
45
+ pip install huimei
46
+ playwright install chromium
47
+ ```
48
+
49
+ ### 方式2: pipx (隔离环境)
50
+ ```bash
51
+ pipx install huimei
52
+ playwright install chromium
53
+ ```
54
+
55
+ ### 方式3: 一键脚本
56
+ ```bash
57
+ curl -fsSL https://raw.githubusercontent.com/huimei-engine/huimei-cli/main/install.sh | bash
58
+ ```
59
+
60
+ ## 快速开始
61
+
62
+ ```bash
63
+ # 登录
64
+ huimei login
65
+
66
+ # 查看支持的平台
67
+ huimei platforms
68
+
69
+ # 查看已绑定账号
70
+ huimei account list
71
+
72
+ # 查看状态
73
+ huimei status
74
+ ```
75
+
76
+ ## AI Agent 集成 (MCP Server)
77
+
78
+ huimei 内置 MCP Server,可供 Claude Code / Hermes / OpenCode 等 AI Agent 直接调用:
79
+
80
+ ### Claude Code 配置
81
+ ```json
82
+ {
83
+ "mcpServers": {
84
+ "huimei": {
85
+ "command": "huimei-mcp-server",
86
+ "args": []
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ ### Hermes Agent 配置
93
+ ```yaml
94
+ mcp_servers:
95
+ huimei:
96
+ command: huimei-mcp-server
97
+ ```
98
+
99
+ ### 可用工具
100
+
101
+ | 工具 | 说明 |
102
+ |------|------|
103
+ | `huimei_login` | 登录账号 |
104
+ | `huimei_status` | 查看状态 |
105
+ | `huimei_logout` | 登出 |
106
+ | `huimei_platforms` | 列出支持平台 |
107
+ | `huimei_accounts` | 列出绑定账号 |
108
+ | `huimei_publish` | 创建发布任务 |
109
+
110
+ ## 架构
111
+
112
+ ```
113
+ CLI (本地) ──HTTP──► Java后端 (云端)
114
+ │ │
115
+ ├─ Playwright ├─ 账号管理
116
+ ├─ Cookie本地存储 ├─ 任务调度
117
+ └─ 住宅IP执行 └─ 订阅计费
118
+ ```
119
+
120
+ CLI 是后端的远程执行器(手臂),所有业务决策由后端(大脑)做出。
121
+
122
+ ## 开发
123
+
124
+ ```bash
125
+ git clone <repo>
126
+ cd huimei-cli
127
+ python -m venv .venv && source .venv/bin/activate
128
+ pip install -e ".[dev]"
129
+ pytest
130
+ ```
131
+
132
+ ## License
133
+
134
+ MIT
huimei-0.1.0/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # 慧媒引擎 CLI (huimei)
2
+
3
+ 多平台社媒自动化发布工具 — 一个命令发布到抖音/快手/B站/小红书/微博等11个平台。
4
+
5
+ ## 安装
6
+
7
+ ### 方式1: pip (推荐)
8
+ ```bash
9
+ pip install huimei
10
+ playwright install chromium
11
+ ```
12
+
13
+ ### 方式2: pipx (隔离环境)
14
+ ```bash
15
+ pipx install huimei
16
+ playwright install chromium
17
+ ```
18
+
19
+ ### 方式3: 一键脚本
20
+ ```bash
21
+ curl -fsSL https://raw.githubusercontent.com/huimei-engine/huimei-cli/main/install.sh | bash
22
+ ```
23
+
24
+ ## 快速开始
25
+
26
+ ```bash
27
+ # 登录
28
+ huimei login
29
+
30
+ # 查看支持的平台
31
+ huimei platforms
32
+
33
+ # 查看已绑定账号
34
+ huimei account list
35
+
36
+ # 查看状态
37
+ huimei status
38
+ ```
39
+
40
+ ## AI Agent 集成 (MCP Server)
41
+
42
+ huimei 内置 MCP Server,可供 Claude Code / Hermes / OpenCode 等 AI Agent 直接调用:
43
+
44
+ ### Claude Code 配置
45
+ ```json
46
+ {
47
+ "mcpServers": {
48
+ "huimei": {
49
+ "command": "huimei-mcp-server",
50
+ "args": []
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ ### Hermes Agent 配置
57
+ ```yaml
58
+ mcp_servers:
59
+ huimei:
60
+ command: huimei-mcp-server
61
+ ```
62
+
63
+ ### 可用工具
64
+
65
+ | 工具 | 说明 |
66
+ |------|------|
67
+ | `huimei_login` | 登录账号 |
68
+ | `huimei_status` | 查看状态 |
69
+ | `huimei_logout` | 登出 |
70
+ | `huimei_platforms` | 列出支持平台 |
71
+ | `huimei_accounts` | 列出绑定账号 |
72
+ | `huimei_publish` | 创建发布任务 |
73
+
74
+ ## 架构
75
+
76
+ ```
77
+ CLI (本地) ──HTTP──► Java后端 (云端)
78
+ │ │
79
+ ├─ Playwright ├─ 账号管理
80
+ ├─ Cookie本地存储 ├─ 任务调度
81
+ └─ 住宅IP执行 └─ 订阅计费
82
+ ```
83
+
84
+ CLI 是后端的远程执行器(手臂),所有业务决策由后端(大脑)做出。
85
+
86
+ ## 开发
87
+
88
+ ```bash
89
+ git clone <repo>
90
+ cd huimei-cli
91
+ python -m venv .venv && source .venv/bin/activate
92
+ pip install -e ".[dev]"
93
+ pytest
94
+ ```
95
+
96
+ ## License
97
+
98
+ MIT
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.4
2
+ Name: huimei
3
+ Version: 0.1.0
4
+ Summary: Multi-platform social media automation CLI — publish to Douyin, XHS, Bilibili, Weibo and 8+ platforms from your terminal
5
+ Author: HuiMei Team
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/huimei-engine/huimei-cli
8
+ Project-URL: Repository, https://codeup.aliyun.com/6832d8ec9c32f0e37238744f/huimei-cli
9
+ Keywords: social-media,automation,cli,douyin,bilibili,xiaohongshu,playwright,cross-posting,marketing
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Internet
20
+ Classifier: Topic :: Multimedia
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: typer>=0.12.0
24
+ Requires-Dist: httpx>=0.27.0
25
+ Requires-Dist: rich>=13.0.0
26
+ Requires-Dist: playwright>=1.40.0
27
+ Requires-Dist: pydantic>=2.0.0
28
+ Requires-Dist: pycryptodome>=3.20.0
29
+ Requires-Dist: keyring>=25.0.0
30
+ Requires-Dist: mcp>=1.0.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
33
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
34
+ Requires-Dist: build; extra == "dev"
35
+ Requires-Dist: twine; extra == "dev"
36
+
37
+ # 慧媒引擎 CLI (huimei)
38
+
39
+ 多平台社媒自动化发布工具 — 一个命令发布到抖音/快手/B站/小红书/微博等11个平台。
40
+
41
+ ## 安装
42
+
43
+ ### 方式1: pip (推荐)
44
+ ```bash
45
+ pip install huimei
46
+ playwright install chromium
47
+ ```
48
+
49
+ ### 方式2: pipx (隔离环境)
50
+ ```bash
51
+ pipx install huimei
52
+ playwright install chromium
53
+ ```
54
+
55
+ ### 方式3: 一键脚本
56
+ ```bash
57
+ curl -fsSL https://raw.githubusercontent.com/huimei-engine/huimei-cli/main/install.sh | bash
58
+ ```
59
+
60
+ ## 快速开始
61
+
62
+ ```bash
63
+ # 登录
64
+ huimei login
65
+
66
+ # 查看支持的平台
67
+ huimei platforms
68
+
69
+ # 查看已绑定账号
70
+ huimei account list
71
+
72
+ # 查看状态
73
+ huimei status
74
+ ```
75
+
76
+ ## AI Agent 集成 (MCP Server)
77
+
78
+ huimei 内置 MCP Server,可供 Claude Code / Hermes / OpenCode 等 AI Agent 直接调用:
79
+
80
+ ### Claude Code 配置
81
+ ```json
82
+ {
83
+ "mcpServers": {
84
+ "huimei": {
85
+ "command": "huimei-mcp-server",
86
+ "args": []
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ ### Hermes Agent 配置
93
+ ```yaml
94
+ mcp_servers:
95
+ huimei:
96
+ command: huimei-mcp-server
97
+ ```
98
+
99
+ ### 可用工具
100
+
101
+ | 工具 | 说明 |
102
+ |------|------|
103
+ | `huimei_login` | 登录账号 |
104
+ | `huimei_status` | 查看状态 |
105
+ | `huimei_logout` | 登出 |
106
+ | `huimei_platforms` | 列出支持平台 |
107
+ | `huimei_accounts` | 列出绑定账号 |
108
+ | `huimei_publish` | 创建发布任务 |
109
+
110
+ ## 架构
111
+
112
+ ```
113
+ CLI (本地) ──HTTP──► Java后端 (云端)
114
+ │ │
115
+ ├─ Playwright ├─ 账号管理
116
+ ├─ Cookie本地存储 ├─ 任务调度
117
+ └─ 住宅IP执行 └─ 订阅计费
118
+ ```
119
+
120
+ CLI 是后端的远程执行器(手臂),所有业务决策由后端(大脑)做出。
121
+
122
+ ## 开发
123
+
124
+ ```bash
125
+ git clone <repo>
126
+ cd huimei-cli
127
+ python -m venv .venv && source .venv/bin/activate
128
+ pip install -e ".[dev]"
129
+ pytest
130
+ ```
131
+
132
+ ## License
133
+
134
+ MIT
@@ -0,0 +1,41 @@
1
+ README.md
2
+ pyproject.toml
3
+ huimei.egg-info/PKG-INFO
4
+ huimei.egg-info/SOURCES.txt
5
+ huimei.egg-info/dependency_links.txt
6
+ huimei.egg-info/entry_points.txt
7
+ huimei.egg-info/requires.txt
8
+ huimei.egg-info/top_level.txt
9
+ huimei_cli/__init__.py
10
+ huimei_cli/api_client.py
11
+ huimei_cli/auth.py
12
+ huimei_cli/config.py
13
+ huimei_cli/main.py
14
+ huimei_cli/mcp_server.py
15
+ huimei_cli/commands/__init__.py
16
+ huimei_cli/commands/account_cmd.py
17
+ huimei_cli/commands/auth_cmd.py
18
+ huimei_cli/commands/publish_cmd.py
19
+ huimei_cli/engine/__init__.py
20
+ huimei_cli/engine/browser.py
21
+ huimei_cli/engine/output.py
22
+ huimei_cli/engine/router.py
23
+ huimei_cli/engine/session.py
24
+ huimei_cli/platforms/__init__.py
25
+ huimei_cli/platforms/registry/__init__.py
26
+ huimei_cli/platforms/registry/_template.py
27
+ huimei_cli/platforms/registry/baijiahao.py
28
+ huimei_cli/platforms/registry/bilibili.py
29
+ huimei_cli/platforms/registry/douyin.py
30
+ huimei_cli/platforms/registry/ks.py
31
+ huimei_cli/platforms/registry/sample.py
32
+ huimei_cli/platforms/registry/tencent.py
33
+ huimei_cli/platforms/registry/tk.py
34
+ huimei_cli/platforms/registry/toutiao.py
35
+ huimei_cli/platforms/registry/weibo.py
36
+ huimei_cli/platforms/registry/weixingongzhonghao.py
37
+ huimei_cli/platforms/registry/xhs.py
38
+ huimei_cli/platforms/registry/zhihu.py
39
+ tests/test_cli.py
40
+ tests/test_core.py
41
+ tests/test_mcp.py
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ huimei = huimei_cli.main:app
3
+ huimei-mcp-server = huimei_cli.mcp_server:main
@@ -0,0 +1,14 @@
1
+ typer>=0.12.0
2
+ httpx>=0.27.0
3
+ rich>=13.0.0
4
+ playwright>=1.40.0
5
+ pydantic>=2.0.0
6
+ pycryptodome>=3.20.0
7
+ keyring>=25.0.0
8
+ mcp>=1.0.0
9
+
10
+ [dev]
11
+ pytest>=8.0.0
12
+ pytest-asyncio>=0.23.0
13
+ build
14
+ twine
@@ -0,0 +1 @@
1
+ huimei_cli
@@ -0,0 +1,2 @@
1
+ """慧媒引擎CLI客户端"""
2
+ __version__ = "0.1.0"
@@ -0,0 +1,105 @@
1
+ """慧媒引擎 Backend API Client"""
2
+ import httpx
3
+
4
+
5
+ class ApiError(Exception):
6
+ """API request error with status code and message."""
7
+ def __init__(self, code: int, message: str):
8
+ self.code = code
9
+ self.message = message
10
+ super().__init__(f"[{code}] {message}")
11
+
12
+
13
+ class ApiClient:
14
+ """Synchronous HTTP client for huimei-engine backend API."""
15
+
16
+ def __init__(self, server_url: str, token: str | None = None, timeout: float = 30.0):
17
+ self.base_url = server_url.rstrip("/")
18
+ self.token = token
19
+ self.timeout = timeout
20
+
21
+ def _headers(self) -> dict:
22
+ headers = {"Content-Type": "application/json"}
23
+ if self.token:
24
+ headers["Authorization"] = f"Bearer {self.token}"
25
+ return headers
26
+
27
+ def _request(self, method: str, path: str, **kwargs) -> dict:
28
+ url = f"{self.base_url}{path}"
29
+ try:
30
+ resp = httpx.request(
31
+ method, url,
32
+ headers=self._headers(),
33
+ timeout=self.timeout,
34
+ **kwargs,
35
+ )
36
+ except httpx.HTTPError as e:
37
+ raise ApiError(0, f"Request failed: {e}") from e
38
+
39
+ if resp.status_code != 200:
40
+ raise ApiError(resp.status_code, f"HTTP {resp.status_code}: {resp.text[:200]}")
41
+
42
+ body = resp.json()
43
+ code = body.get("code", -1)
44
+ if code != 200:
45
+ raise ApiError(code, body.get("message", "Unknown error"))
46
+ return body.get("data")
47
+
48
+ def _get(self, path: str, **params) -> dict:
49
+ return self._request("GET", path, params=params or None)
50
+
51
+ def _post(self, path: str, data: dict = None) -> dict:
52
+ return self._request("POST", path, json=data)
53
+
54
+ def _put(self, path: str, data: dict = None) -> dict:
55
+ return self._request("PUT", path, json=data)
56
+
57
+ # ── Auth ──────────────────────────────────────────────
58
+
59
+ def login(self, username: str, password: str) -> dict:
60
+ """Login and store JWT token. Returns user/token data."""
61
+ result = self._post("/api/v1/auth/login", {
62
+ "username": username,
63
+ "password": password,
64
+ })
65
+ if result and "token" in result:
66
+ self.token = result["token"]
67
+ return result
68
+
69
+ # ── Subscription ──────────────────────────────────────
70
+
71
+ def get_subscription_info(self) -> dict:
72
+ """Get current subscription/plan info."""
73
+ return self._get("/api/v1/subscription/current")
74
+
75
+ # ── Accounts & Platforms ──────────────────────────────
76
+
77
+ def get_accounts(self) -> list:
78
+ """List all bound social media accounts."""
79
+ return self._get("/api/v1/accounts")
80
+
81
+ def get_platforms(self) -> list:
82
+ """List all supported platforms."""
83
+ return self._get("/api/v1/platforms")
84
+
85
+ def get_publish_params_config(self, platform_id: str) -> dict:
86
+ """Get publish parameter config for a specific platform."""
87
+ return self._get(f"/api/v1/platforms/{platform_id}/publish-params-config")
88
+
89
+ # ── Publish Tasks ─────────────────────────────────────
90
+
91
+ def create_task(self, task_data: dict) -> dict:
92
+ """Create a new publish task."""
93
+ return self._post("/api/v1/publish", task_data)
94
+
95
+ def report_task_result(self, task_uuid: str, result: dict) -> dict:
96
+ """Report the result of a CLI-executed task."""
97
+ return self._put(f"/api/v1/cli/tasks/{task_uuid}/report", result)
98
+
99
+ def register_device(self, device_id: str, device_name: str, os_type: str) -> dict:
100
+ """Register CLI device with backend."""
101
+ return self._post("/api/v1/cli/device/register", {
102
+ "device_id": device_id,
103
+ "device_name": device_name,
104
+ "os_type": os_type,
105
+ })
@@ -0,0 +1,72 @@
1
+ """Authentication management for huimei-cli."""
2
+
3
+ import json
4
+ import base64
5
+
6
+ from huimei_cli.config import get_config, save_config, get_server_url, save_token
7
+ from huimei_cli.api_client import ApiClient, ApiError
8
+
9
+
10
+ def do_login(username: str, password: str, server_url: str = None) -> bool:
11
+ """Login to the huimei server and save token to config.
12
+
13
+ Args:
14
+ username: User's username.
15
+ password: User's password.
16
+ server_url: Optional server URL override.
17
+
18
+ Returns:
19
+ True if login succeeded, False otherwise.
20
+ """
21
+ url = server_url or get_server_url()
22
+ client = ApiClient(server_url=url)
23
+ try:
24
+ data = client.login(username, password)
25
+ token = data.get("token") if isinstance(data, dict) else None
26
+ if not token:
27
+ return False
28
+ save_token(token)
29
+ # Also persist server_url if overridden
30
+ if server_url:
31
+ cfg = get_config()
32
+ cfg["server_url"] = server_url
33
+ save_config(cfg)
34
+ return True
35
+ except (ApiError, Exception):
36
+ return False
37
+
38
+
39
+ def is_logged_in() -> bool:
40
+ """Check whether a valid token exists in config."""
41
+ cfg = get_config()
42
+ return bool(cfg.get("token"))
43
+
44
+
45
+ def get_current_user() -> dict | None:
46
+ """Decode the JWT token payload to get current user info.
47
+
48
+ Decodes without verification — only reads the payload claims.
49
+
50
+ Returns:
51
+ Dict of user claims from token, or None if not logged in.
52
+ """
53
+ cfg = get_config()
54
+ token = cfg.get("token")
55
+ if not token:
56
+ return None
57
+ try:
58
+ payload_b64 = token.split(".")[1]
59
+ padding = 4 - len(payload_b64) % 4
60
+ if padding != 4:
61
+ payload_b64 += "=" * padding
62
+ payload_bytes = base64.urlsafe_b64decode(payload_b64)
63
+ return json.loads(payload_bytes)
64
+ except (IndexError, ValueError, json.JSONDecodeError):
65
+ return None
66
+
67
+
68
+ def logout() -> None:
69
+ """Clear authentication token from config."""
70
+ cfg = get_config()
71
+ cfg.pop("token", None)
72
+ save_config(cfg)
@@ -0,0 +1 @@
1
+ """CLI commands package."""