drinkzen-admin-cli 0.2.4__tar.gz → 0.3.3__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.
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/PKG-INFO +32 -1
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/README.md +31 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin/__init__.py +1 -1
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin/cli.py +45 -0
- drinkzen_admin_cli-0.3.3/drinkzen_admin/skill.py +37 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin_cli.egg-info/PKG-INFO +32 -1
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin_cli.egg-info/SOURCES.txt +2 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/pyproject.toml +1 -1
- drinkzen_admin_cli-0.3.3/tests/test_skill.py +26 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/tests/test_standalone_cli.py +28 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin/client.py +0 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin/config.py +0 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin/formatting.py +0 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin/menu_options.py +0 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin_cli.egg-info/dependency_links.txt +0 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin_cli.egg-info/entry_points.txt +0 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin_cli.egg-info/top_level.txt +0 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/setup.cfg +0 -0
- {drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/tests/test_config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drinkzen-admin-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Standalone CLI client for DrinkZen Admin operations
|
|
5
5
|
Author: DrinkZen Team
|
|
6
6
|
License: MIT
|
|
@@ -64,6 +64,34 @@ PYTHONPATH=packages/admin-cli python3 -m drinkzen_admin.cli config show
|
|
|
64
64
|
|
|
65
65
|
---
|
|
66
66
|
|
|
67
|
+
## Agent Skill 安装
|
|
68
|
+
|
|
69
|
+
`drinkzen-admin` 提供与具体 AI 工具无关的运营使用手册。默认安装到当前项目的 `.agents/skills`:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
drinkzen-admin skill install
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
如需安装到当前用户的全局 Agent Skill 目录:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
drinkzen-admin skill install --scope global
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
查询目标路径或更新已有 Skill:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
drinkzen-admin skill path --scope project --json
|
|
85
|
+
drinkzen-admin skill path --scope global --json
|
|
86
|
+
drinkzen-admin skill install --force
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
项目级安装默认使用当前目录,也可以指定项目目录:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
drinkzen-admin skill install --scope project --project-dir /path/to/project
|
|
93
|
+
```
|
|
94
|
+
|
|
67
95
|
## 密钥与持久化配置管理 (`config`)
|
|
68
96
|
|
|
69
97
|
`drinkzen-admin` 提供了内置的密钥持久化管理,避免每次在终端手动输入敏感 Token 或将其留在 Bash 历史记录中。
|
|
@@ -128,6 +156,9 @@ drinkzen-admin brand update 霸王茶姬 --name "霸王茶姬 CHAGEE" --alias "C
|
|
|
128
156
|
|
|
129
157
|
# 上传品牌 Logo 并标注数据置信度
|
|
130
158
|
drinkzen-admin brand set-logo 霸王茶姬 ./logo.png --confidence verified --source-name "官方小程序"
|
|
159
|
+
|
|
160
|
+
# 只读核对数据库 Logo 引用与 COS 文件,识别缺失引用与孤儿对象
|
|
161
|
+
drinkzen-admin brand audit-logos --json
|
|
131
162
|
```
|
|
132
163
|
|
|
133
164
|
### 2. 菜单模板管理 (`menu-template`)
|
|
@@ -42,6 +42,34 @@ PYTHONPATH=packages/admin-cli python3 -m drinkzen_admin.cli config show
|
|
|
42
42
|
|
|
43
43
|
---
|
|
44
44
|
|
|
45
|
+
## Agent Skill 安装
|
|
46
|
+
|
|
47
|
+
`drinkzen-admin` 提供与具体 AI 工具无关的运营使用手册。默认安装到当前项目的 `.agents/skills`:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
drinkzen-admin skill install
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
如需安装到当前用户的全局 Agent Skill 目录:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
drinkzen-admin skill install --scope global
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
查询目标路径或更新已有 Skill:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
drinkzen-admin skill path --scope project --json
|
|
63
|
+
drinkzen-admin skill path --scope global --json
|
|
64
|
+
drinkzen-admin skill install --force
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
项目级安装默认使用当前目录,也可以指定项目目录:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
drinkzen-admin skill install --scope project --project-dir /path/to/project
|
|
71
|
+
```
|
|
72
|
+
|
|
45
73
|
## 密钥与持久化配置管理 (`config`)
|
|
46
74
|
|
|
47
75
|
`drinkzen-admin` 提供了内置的密钥持久化管理,避免每次在终端手动输入敏感 Token 或将其留在 Bash 历史记录中。
|
|
@@ -106,6 +134,9 @@ drinkzen-admin brand update 霸王茶姬 --name "霸王茶姬 CHAGEE" --alias "C
|
|
|
106
134
|
|
|
107
135
|
# 上传品牌 Logo 并标注数据置信度
|
|
108
136
|
drinkzen-admin brand set-logo 霸王茶姬 ./logo.png --confidence verified --source-name "官方小程序"
|
|
137
|
+
|
|
138
|
+
# 只读核对数据库 Logo 引用与 COS 文件,识别缺失引用与孤儿对象
|
|
139
|
+
drinkzen-admin brand audit-logos --json
|
|
109
140
|
```
|
|
110
141
|
|
|
111
142
|
### 2. 菜单模板管理 (`menu-template`)
|
|
@@ -12,6 +12,7 @@ from .client import AdminCLIClient
|
|
|
12
12
|
from .config import cmd_config_path, cmd_config_set, cmd_config_show
|
|
13
13
|
from .formatting import format_cli_output
|
|
14
14
|
from .menu_options import normalize_menu_option_config
|
|
15
|
+
from .skill import install_skill, skill_path
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
# ----------------------------------------------------------------------
|
|
@@ -62,6 +63,16 @@ def cmd_brand_show(
|
|
|
62
63
|
return 0
|
|
63
64
|
|
|
64
65
|
|
|
66
|
+
def cmd_brand_audit_logos(client: AdminCLIClient, is_json: bool = False) -> int:
|
|
67
|
+
"""Print the API's read-only COS/database logo consistency audit."""
|
|
68
|
+
status, data = client.request("GET", "/api/admin/brands/logo-audit")
|
|
69
|
+
if status != 200:
|
|
70
|
+
print(format_cli_output({"error": data}, is_json))
|
|
71
|
+
return 1
|
|
72
|
+
print(format_cli_output(data, is_json))
|
|
73
|
+
return 0
|
|
74
|
+
|
|
75
|
+
|
|
65
76
|
def cmd_brand_update(
|
|
66
77
|
client: AdminCLIClient,
|
|
67
78
|
brand_id_or_name: str,
|
|
@@ -404,6 +415,19 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
404
415
|
c_show = config_sub.add_parser("show", help="Show active configuration with masked secrets", parents=[common_parser])
|
|
405
416
|
c_path = config_sub.add_parser("path", help="Print configuration file path", parents=[common_parser])
|
|
406
417
|
|
|
418
|
+
# skill
|
|
419
|
+
skill_parser = subparsers.add_parser("skill", help="Install the agent-neutral DrinkZen Admin Skill")
|
|
420
|
+
skill_sub = skill_parser.add_subparsers(dest="skill_action", required=True)
|
|
421
|
+
s_install = skill_sub.add_parser("install", help="Download the Skill into .agents/skills")
|
|
422
|
+
s_install.add_argument("--scope", choices=["project", "global"], default="project")
|
|
423
|
+
s_install.add_argument("--project-dir", default=None, help="Project directory for project scope (default: current directory)")
|
|
424
|
+
s_install.add_argument("--force", action="store_true", help="Replace an existing Skill")
|
|
425
|
+
s_install.add_argument("--json", action="store_true", help="Output JSON format")
|
|
426
|
+
s_path = skill_sub.add_parser("path", help="Show the target Skill path")
|
|
427
|
+
s_path.add_argument("--scope", choices=["project", "global"], default="project")
|
|
428
|
+
s_path.add_argument("--project-dir", default=None)
|
|
429
|
+
s_path.add_argument("--json", action="store_true", help="Output JSON format")
|
|
430
|
+
|
|
407
431
|
# brand
|
|
408
432
|
brand_parser = subparsers.add_parser("brand", help="Brand operations", parents=[common_parser])
|
|
409
433
|
brand_sub = brand_parser.add_subparsers(dest="brand_action", required=True)
|
|
@@ -415,6 +439,12 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
415
439
|
b_show = brand_sub.add_parser("show", help="Show brand details", parents=[common_parser])
|
|
416
440
|
b_show.add_argument("brand", help="Brand ID or name")
|
|
417
441
|
|
|
442
|
+
brand_sub.add_parser(
|
|
443
|
+
"audit-logos",
|
|
444
|
+
help="Read-only audit of brand Logo references against object storage",
|
|
445
|
+
parents=[common_parser],
|
|
446
|
+
)
|
|
447
|
+
|
|
418
448
|
b_update = brand_sub.add_parser("update", help="Update brand information", parents=[common_parser])
|
|
419
449
|
b_update.add_argument("brand", help="Brand ID or name")
|
|
420
450
|
b_update.add_argument("--name", default=None, help="New brand name")
|
|
@@ -470,6 +500,19 @@ def main(args: list[str] | None = None) -> int:
|
|
|
470
500
|
is_json = getattr(parsed, "json", False)
|
|
471
501
|
dry_run = getattr(parsed, "dry_run", False)
|
|
472
502
|
|
|
503
|
+
if parsed.subcommand == "skill":
|
|
504
|
+
target = skill_path(parsed.scope, parsed.project_dir)
|
|
505
|
+
if parsed.skill_action == "path":
|
|
506
|
+
print(format_cli_output({"path": str(target), "scope": parsed.scope}, parsed.json))
|
|
507
|
+
return 0
|
|
508
|
+
try:
|
|
509
|
+
installed = install_skill(parsed.scope, parsed.project_dir, parsed.force)
|
|
510
|
+
print(format_cli_output({"installed": True, "path": str(installed), "scope": parsed.scope}, parsed.json))
|
|
511
|
+
return 0
|
|
512
|
+
except Exception as exc:
|
|
513
|
+
print(format_cli_output({"installed": False, "error": str(exc), "path": str(target)}, parsed.json))
|
|
514
|
+
return 1
|
|
515
|
+
|
|
473
516
|
# Config commands
|
|
474
517
|
if parsed.subcommand == "config":
|
|
475
518
|
if parsed.config_action == "set":
|
|
@@ -488,6 +531,8 @@ def main(args: list[str] | None = None) -> int:
|
|
|
488
531
|
return cmd_brand_list(client, search=parsed.search, active_only=parsed.active_only, is_json=is_json)
|
|
489
532
|
if parsed.brand_action == "show":
|
|
490
533
|
return cmd_brand_show(client, brand_id_or_name=parsed.brand, is_json=is_json)
|
|
534
|
+
if parsed.brand_action == "audit-logos":
|
|
535
|
+
return cmd_brand_audit_logos(client, is_json=is_json)
|
|
491
536
|
if parsed.brand_action == "update":
|
|
492
537
|
return cmd_brand_update(
|
|
493
538
|
client,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Install the DrinkZen Admin Agent Skill without binding to a specific agent."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import urllib.request
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
SKILL_NAME = "drinkzen-admin"
|
|
9
|
+
SKILL_URL = "https://drinkzen.cn/skills/drinkzen-admin/SKILL.md"
|
|
10
|
+
SKILL_USER_AGENT = "DrinkZenAdminCLI/1.0 (+https://drinkzen.cn)"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def skill_path(scope: str = "project", project_dir: str | None = None) -> Path:
|
|
14
|
+
if scope == "global":
|
|
15
|
+
root = Path.home() / ".agents" / "skills"
|
|
16
|
+
else:
|
|
17
|
+
root = Path(project_dir or ".").expanduser().resolve() / ".agents" / "skills"
|
|
18
|
+
return root / SKILL_NAME / "SKILL.md"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def install_skill(
|
|
22
|
+
scope: str = "project",
|
|
23
|
+
project_dir: str | None = None,
|
|
24
|
+
force: bool = False,
|
|
25
|
+
url: str = SKILL_URL,
|
|
26
|
+
) -> Path:
|
|
27
|
+
destination = skill_path(scope, project_dir)
|
|
28
|
+
if destination.exists() and not force:
|
|
29
|
+
raise FileExistsError(f"Skill already exists: {destination}. Use --force to replace it.")
|
|
30
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
31
|
+
request = urllib.request.Request(url, headers={"User-Agent": SKILL_USER_AGENT})
|
|
32
|
+
with urllib.request.urlopen(request, timeout=20) as response:
|
|
33
|
+
content = response.read()
|
|
34
|
+
if not content:
|
|
35
|
+
raise RuntimeError("Downloaded Skill is empty")
|
|
36
|
+
destination.write_bytes(content)
|
|
37
|
+
return destination
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drinkzen-admin-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Standalone CLI client for DrinkZen Admin operations
|
|
5
5
|
Author: DrinkZen Team
|
|
6
6
|
License: MIT
|
|
@@ -64,6 +64,34 @@ PYTHONPATH=packages/admin-cli python3 -m drinkzen_admin.cli config show
|
|
|
64
64
|
|
|
65
65
|
---
|
|
66
66
|
|
|
67
|
+
## Agent Skill 安装
|
|
68
|
+
|
|
69
|
+
`drinkzen-admin` 提供与具体 AI 工具无关的运营使用手册。默认安装到当前项目的 `.agents/skills`:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
drinkzen-admin skill install
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
如需安装到当前用户的全局 Agent Skill 目录:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
drinkzen-admin skill install --scope global
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
查询目标路径或更新已有 Skill:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
drinkzen-admin skill path --scope project --json
|
|
85
|
+
drinkzen-admin skill path --scope global --json
|
|
86
|
+
drinkzen-admin skill install --force
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
项目级安装默认使用当前目录,也可以指定项目目录:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
drinkzen-admin skill install --scope project --project-dir /path/to/project
|
|
93
|
+
```
|
|
94
|
+
|
|
67
95
|
## 密钥与持久化配置管理 (`config`)
|
|
68
96
|
|
|
69
97
|
`drinkzen-admin` 提供了内置的密钥持久化管理,避免每次在终端手动输入敏感 Token 或将其留在 Bash 历史记录中。
|
|
@@ -128,6 +156,9 @@ drinkzen-admin brand update 霸王茶姬 --name "霸王茶姬 CHAGEE" --alias "C
|
|
|
128
156
|
|
|
129
157
|
# 上传品牌 Logo 并标注数据置信度
|
|
130
158
|
drinkzen-admin brand set-logo 霸王茶姬 ./logo.png --confidence verified --source-name "官方小程序"
|
|
159
|
+
|
|
160
|
+
# 只读核对数据库 Logo 引用与 COS 文件,识别缺失引用与孤儿对象
|
|
161
|
+
drinkzen-admin brand audit-logos --json
|
|
131
162
|
```
|
|
132
163
|
|
|
133
164
|
### 2. 菜单模板管理 (`menu-template`)
|
{drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin_cli.egg-info/SOURCES.txt
RENAMED
|
@@ -6,10 +6,12 @@ drinkzen_admin/client.py
|
|
|
6
6
|
drinkzen_admin/config.py
|
|
7
7
|
drinkzen_admin/formatting.py
|
|
8
8
|
drinkzen_admin/menu_options.py
|
|
9
|
+
drinkzen_admin/skill.py
|
|
9
10
|
drinkzen_admin_cli.egg-info/PKG-INFO
|
|
10
11
|
drinkzen_admin_cli.egg-info/SOURCES.txt
|
|
11
12
|
drinkzen_admin_cli.egg-info/dependency_links.txt
|
|
12
13
|
drinkzen_admin_cli.egg-info/entry_points.txt
|
|
13
14
|
drinkzen_admin_cli.egg-info/top_level.txt
|
|
14
15
|
tests/test_config.py
|
|
16
|
+
tests/test_skill.py
|
|
15
17
|
tests/test_standalone_cli.py
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from tempfile import TemporaryDirectory
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
|
|
5
|
+
from drinkzen_admin.skill import SKILL_USER_AGENT, install_skill
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SkillResponse:
|
|
9
|
+
def __enter__(self) -> "SkillResponse":
|
|
10
|
+
return self
|
|
11
|
+
|
|
12
|
+
def __exit__(self, exc_type: object, exc_value: object, traceback: object) -> None:
|
|
13
|
+
return None
|
|
14
|
+
|
|
15
|
+
def read(self) -> bytes:
|
|
16
|
+
return b"---\nname: drinkzen-admin\n---\n"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_install_skill_identifies_the_cli_request() -> None:
|
|
20
|
+
with TemporaryDirectory() as temp_dir:
|
|
21
|
+
with patch("urllib.request.urlopen", return_value=SkillResponse()) as urlopen:
|
|
22
|
+
destination = install_skill(project_dir=temp_dir)
|
|
23
|
+
|
|
24
|
+
request = urlopen.call_args.args[0]
|
|
25
|
+
assert request.get_header("User-agent") == SKILL_USER_AGENT
|
|
26
|
+
assert Path(destination).read_text(encoding="utf-8").startswith("---")
|
|
@@ -71,6 +71,34 @@ class TestStandaloneCLI(unittest.TestCase):
|
|
|
71
71
|
self.assertTrue(output.get("dry_run"))
|
|
72
72
|
self.assertEqual(output["proposed"]["name"], "新名称")
|
|
73
73
|
|
|
74
|
+
@patch("drinkzen_admin.cli.AdminCLIClient")
|
|
75
|
+
def test_brand_audit_logos_command(self, mock_client_cls):
|
|
76
|
+
mock_client = MagicMock()
|
|
77
|
+
mock_client.request.return_value = (
|
|
78
|
+
200,
|
|
79
|
+
{
|
|
80
|
+
"backend": "CosObjectStorage",
|
|
81
|
+
"total_brands": 14,
|
|
82
|
+
"referenced_logo_count": 9,
|
|
83
|
+
"missing_referenced_objects": [],
|
|
84
|
+
"recoverable_unlinked_objects": [],
|
|
85
|
+
"orphan_object_keys": ["brands/old/logo.png"],
|
|
86
|
+
},
|
|
87
|
+
)
|
|
88
|
+
mock_client_cls.return_value = mock_client
|
|
89
|
+
|
|
90
|
+
buf = io.StringIO()
|
|
91
|
+
with patch("sys.argv", ["drinkzen-admin", "brand", "audit-logos", "--json"]):
|
|
92
|
+
with redirect_stdout(buf):
|
|
93
|
+
exit_code = main()
|
|
94
|
+
|
|
95
|
+
self.assertEqual(exit_code, 0)
|
|
96
|
+
output = json.loads(buf.getvalue())
|
|
97
|
+
self.assertEqual(output["referenced_logo_count"], 9)
|
|
98
|
+
mock_client.request.assert_called_once_with(
|
|
99
|
+
"GET", "/api/admin/brands/logo-audit"
|
|
100
|
+
)
|
|
101
|
+
|
|
74
102
|
def test_menu_template_validate_command(self):
|
|
75
103
|
valid_template = json.dumps({
|
|
76
104
|
"optionGroups": [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin_cli.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{drinkzen_admin_cli-0.2.4 → drinkzen_admin_cli-0.3.3}/drinkzen_admin_cli.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|