web-presentation-cli 0.1.0__tar.gz → 0.1.1__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.
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/PKG-INFO +4 -2
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/README.md +2 -1
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/pyproject.toml +2 -1
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/__init__.py +1 -1
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/cli.py +1 -2
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/client.py +1 -1
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/asset.py +44 -29
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/catalog.py +13 -12
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/component.py +71 -44
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/job.py +11 -5
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/page.py +41 -20
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/project.py +38 -17
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/style.py +24 -13
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/system.py +6 -33
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/theme.py +25 -14
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/workspace.py +5 -4
- web_presentation_cli-0.1.1/src/wp/openapi_help.py +154 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp_api_client/client.py +26 -5
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/tests/test_capability_commands.py +1 -1
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/tests/test_cli_commands.py +2 -2
- web_presentation_cli-0.1.1/tests/test_openapi_help.py +113 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/.gitignore +0 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/hatch_build.py +0 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/__init__.py +0 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/auth.py +0 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/common.py +0 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/doctor.py +0 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/profile.py +0 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/commands/screenshot.py +0 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/config.py +0 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp/formatter.py +0 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/src/wp_api_client/__init__.py +0 -0
- {web_presentation_cli-0.1.0 → web_presentation_cli-0.1.1}/tests/test_screenshot_command.py +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: web-presentation-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Web Presentation CLI - 面向 AI 演示文稿创作平台的命令行与 Agent 工具包
|
|
5
5
|
Project-URL: Homepage, https://github.com/LLMxPM/web-presentation-agent-kit
|
|
6
6
|
Project-URL: Repository, https://github.com/LLMxPM/web-presentation-agent-kit
|
|
7
7
|
Project-URL: Issues, https://github.com/LLMxPM/web-presentation-agent-kit/issues
|
|
8
|
+
License: Apache-2.0
|
|
8
9
|
Requires-Python: >=3.11
|
|
9
10
|
Requires-Dist: click>=8.1.7
|
|
10
11
|
Requires-Dist: httpx>=0.27.0
|
|
@@ -55,10 +56,11 @@ wp component list --scope suggested --project-id <project_id>
|
|
|
55
56
|
wp asset content get <asset_id>
|
|
56
57
|
wp theme list
|
|
57
58
|
wp style list
|
|
58
|
-
wp --json guide list
|
|
59
59
|
wp job wait <job_id>
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
复杂写入参数使用 `--payload-file`、`--edits-file`、`--content-file`、`--route-file` 和 `--ids-file`。Build、产物下载、Agent 运行、图片能力、Restore 和 MCP 不属于当前 CLI。
|
|
63
63
|
|
|
64
|
+
叶子命令的 `--help` 会从当前 Profile 的 Backend `/openapi.json` 加载请求参数和完整 Schema;服务不可达时仍返回本地语法帮助,不缓存 Schema。
|
|
65
|
+
|
|
64
66
|
写入命令支持 `--idempotency-key <key>`;网络超时后需要重放同一业务请求时复用原 key,不要把同一个 key 用于不同请求。
|
|
@@ -41,10 +41,11 @@ wp component list --scope suggested --project-id <project_id>
|
|
|
41
41
|
wp asset content get <asset_id>
|
|
42
42
|
wp theme list
|
|
43
43
|
wp style list
|
|
44
|
-
wp --json guide list
|
|
45
44
|
wp job wait <job_id>
|
|
46
45
|
```
|
|
47
46
|
|
|
48
47
|
复杂写入参数使用 `--payload-file`、`--edits-file`、`--content-file`、`--route-file` 和 `--ids-file`。Build、产物下载、Agent 运行、图片能力、Restore 和 MCP 不属于当前 CLI。
|
|
49
48
|
|
|
49
|
+
叶子命令的 `--help` 会从当前 Profile 的 Backend `/openapi.json` 加载请求参数和完整 Schema;服务不可达时仍返回本地语法帮助,不缓存 Schema。
|
|
50
|
+
|
|
50
51
|
写入命令支持 `--idempotency-key <key>`;网络超时后需要重放同一业务请求时复用原 key,不要把同一个 key 用于不同请求。
|
|
@@ -4,9 +4,10 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "web-presentation-cli"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.1"
|
|
8
8
|
description = "Web Presentation CLI - 面向 AI 演示文稿创作平台的命令行与 Agent 工具包"
|
|
9
9
|
readme = "README.md"
|
|
10
|
+
license = { text = "Apache-2.0" }
|
|
10
11
|
requires-python = ">=3.11"
|
|
11
12
|
dependencies = [
|
|
12
13
|
"click>=8.1.7",
|
|
@@ -17,7 +17,7 @@ from wp.commands.project import project_group
|
|
|
17
17
|
from wp.commands.style import style_group
|
|
18
18
|
from wp.commands.theme import theme_group
|
|
19
19
|
from wp.commands.workspace import workspace_group
|
|
20
|
-
from wp.commands.system import
|
|
20
|
+
from wp.commands.system import standards_group, system_group
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
@click.group()
|
|
@@ -48,7 +48,6 @@ main.add_command(doctor_cmd)
|
|
|
48
48
|
main.add_command(profile_group)
|
|
49
49
|
main.add_command(system_group)
|
|
50
50
|
main.add_command(standards_group)
|
|
51
|
-
main.add_command(guide_group)
|
|
52
51
|
main.add_command(runtime_kit_group)
|
|
53
52
|
main.add_command(font_group)
|
|
54
53
|
|
|
@@ -19,7 +19,7 @@ class ApiClient(SharedApiClient):
|
|
|
19
19
|
endpoint=profile.endpoint,
|
|
20
20
|
token=profile.token,
|
|
21
21
|
workspace_id=workspace_id or profile.default_workspace_id,
|
|
22
|
-
user_agent="web-presentation-cli/0.1.
|
|
22
|
+
user_agent="web-presentation-cli/0.1.1",
|
|
23
23
|
idempotency_key=idempotency_key,
|
|
24
24
|
)
|
|
25
25
|
|
|
@@ -15,11 +15,11 @@ from wp.commands.common import (
|
|
|
15
15
|
output_result,
|
|
16
16
|
read_json_file,
|
|
17
17
|
read_text_file,
|
|
18
|
-
require_array,
|
|
19
18
|
require_ids,
|
|
20
19
|
require_object,
|
|
21
20
|
)
|
|
22
21
|
from wp.formatter import print_table
|
|
22
|
+
from wp.openapi_help import contract, openapi_command
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
ASSET_TYPES = ["image", "icon", "font", "video", "drawio", "mermaid", "chart", "formula"]
|
|
@@ -30,11 +30,11 @@ def asset_group() -> None:
|
|
|
30
30
|
"""工作空间静态资源管理。"""
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
@asset_group
|
|
34
|
-
@click.option("--page", default=1, type=int)
|
|
35
|
-
@click.option("--page-size", default=50, type=int)
|
|
36
|
-
@click.option("--type", "asset_type", type=click.Choice(ASSET_TYPES))
|
|
37
|
-
@click.option("--keyword")
|
|
33
|
+
@openapi_command(asset_group, "list", contract("GET", "/api/v1/assets"))
|
|
34
|
+
@click.option("--page", default=1, type=int, show_default=True, help="结果页码")
|
|
35
|
+
@click.option("--page-size", default=50, type=int, show_default=True, help="每页返回数量")
|
|
36
|
+
@click.option("--type", "asset_type", type=click.Choice(ASSET_TYPES), help="按资源业务类型筛选")
|
|
37
|
+
@click.option("--keyword", help="按资源名称、说明或标签搜索")
|
|
38
38
|
@click.pass_context
|
|
39
39
|
def list_assets_cmd(ctx: click.Context, page: int, page_size: int, asset_type: str | None, keyword: str | None) -> None:
|
|
40
40
|
"""查询工作空间资源。"""
|
|
@@ -51,7 +51,7 @@ def list_assets_cmd(ctx: click.Context, page: int, page_size: int, asset_type: s
|
|
|
51
51
|
handle_api_error("获取资源列表失败", err)
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
@asset_group
|
|
54
|
+
@openapi_command(asset_group, "get", contract("GET", "/api/v1/assets/{asset_id}"))
|
|
55
55
|
@click.argument("asset_id", type=int)
|
|
56
56
|
@click.pass_context
|
|
57
57
|
def get_asset_cmd(ctx: click.Context, asset_id: int) -> None:
|
|
@@ -63,11 +63,16 @@ def get_asset_cmd(ctx: click.Context, asset_id: int) -> None:
|
|
|
63
63
|
handle_api_error("获取资源详情失败", err)
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
@
|
|
66
|
+
@openapi_command(
|
|
67
|
+
asset_group,
|
|
68
|
+
"upload",
|
|
69
|
+
contract("POST", "/api/v1/assets"),
|
|
70
|
+
examples=("wp asset upload ./hero.png --type image --name hero-image --idempotency-key asset-hero-image",),
|
|
71
|
+
)
|
|
67
72
|
@click.argument("file_path", type=click.Path(exists=True, dir_okay=False))
|
|
68
|
-
@click.option("--type", "asset_type", type=click.Choice(ASSET_TYPES), required=True)
|
|
69
|
-
@click.option("--name")
|
|
70
|
-
@click.option("--description")
|
|
73
|
+
@click.option("--type", "asset_type", type=click.Choice(ASSET_TYPES), required=True, help="上传资源类型")
|
|
74
|
+
@click.option("--name", help="平台逻辑名;默认使用文件名主干")
|
|
75
|
+
@click.option("--description", help="资源内容、来源和使用场景说明")
|
|
71
76
|
@idempotency_key_option
|
|
72
77
|
@click.pass_context
|
|
73
78
|
def upload_asset_cmd(ctx: click.Context, file_path: str, asset_type: str, name: str | None, description: str | None) -> None:
|
|
@@ -86,8 +91,13 @@ def upload_asset_cmd(ctx: click.Context, file_path: str, asset_type: str, name:
|
|
|
86
91
|
handle_api_error("上传资源失败", err)
|
|
87
92
|
|
|
88
93
|
|
|
89
|
-
@
|
|
90
|
-
|
|
94
|
+
@openapi_command(
|
|
95
|
+
asset_group,
|
|
96
|
+
"create",
|
|
97
|
+
contract("POST", "/api/v1/assets/content"),
|
|
98
|
+
examples=("wp asset create --payload-file ./asset.json --content-file ./diagram.mmd --idempotency-key asset-diagram",),
|
|
99
|
+
)
|
|
100
|
+
@click.option("--payload-file", type=click.Path(exists=True, dir_okay=False), required=True, help="文本资源创建 JSON 请求体")
|
|
91
101
|
@click.option("--content-file", type=click.Path(exists=True, dir_okay=False), help="覆盖 JSON 中 content 的文本文件")
|
|
92
102
|
@idempotency_key_option
|
|
93
103
|
@click.pass_context
|
|
@@ -108,7 +118,7 @@ def asset_content_group() -> None:
|
|
|
108
118
|
"""可编辑文本资源内容。"""
|
|
109
119
|
|
|
110
120
|
|
|
111
|
-
@asset_content_group
|
|
121
|
+
@openapi_command(asset_content_group, "get", contract("GET", "/api/v1/assets/{asset_id}/content"))
|
|
112
122
|
@click.argument("asset_id", type=int)
|
|
113
123
|
@click.pass_context
|
|
114
124
|
def get_asset_content_cmd(ctx: click.Context, asset_id: int) -> None:
|
|
@@ -120,10 +130,10 @@ def get_asset_content_cmd(ctx: click.Context, asset_id: int) -> None:
|
|
|
120
130
|
handle_api_error("读取资源内容失败", err)
|
|
121
131
|
|
|
122
132
|
|
|
123
|
-
@asset_content_group
|
|
133
|
+
@openapi_command(asset_content_group, "update", contract("PUT", "/api/v1/assets/{asset_id}/content"))
|
|
124
134
|
@click.argument("asset_id", type=int)
|
|
125
|
-
@click.option("--content-file", type=click.Path(exists=True, dir_okay=False), required=True)
|
|
126
|
-
@click.option("--change-note")
|
|
135
|
+
@click.option("--content-file", type=click.Path(exists=True, dir_okay=False), required=True, help="要写入的完整 UTF-8 文本内容")
|
|
136
|
+
@click.option("--change-note", help="本次完整内容替换的变更说明")
|
|
127
137
|
@idempotency_key_option
|
|
128
138
|
@click.pass_context
|
|
129
139
|
def update_asset_content_cmd(ctx: click.Context, asset_id: int, content_file: str, change_note: str | None) -> None:
|
|
@@ -135,9 +145,9 @@ def update_asset_content_cmd(ctx: click.Context, asset_id: int, content_file: st
|
|
|
135
145
|
handle_api_error("更新资源内容失败", err)
|
|
136
146
|
|
|
137
147
|
|
|
138
|
-
@asset_content_group
|
|
148
|
+
@openapi_command(asset_content_group, "preview", contract("POST", "/api/v1/assets/{asset_id}/content/preview"))
|
|
139
149
|
@click.argument("asset_id", type=int)
|
|
140
|
-
@click.option("--content-file", type=click.Path(exists=True, dir_okay=False), required=True)
|
|
150
|
+
@click.option("--content-file", type=click.Path(exists=True, dir_okay=False), required=True, help="用于生成差异且不会写入的候选 UTF-8 文本")
|
|
141
151
|
@click.pass_context
|
|
142
152
|
def preview_asset_content_cmd(ctx: click.Context, asset_id: int, content_file: str) -> None:
|
|
143
153
|
"""预览资源文本内容差异。"""
|
|
@@ -153,8 +163,8 @@ def asset_tags_group() -> None:
|
|
|
153
163
|
"""资源标签。"""
|
|
154
164
|
|
|
155
165
|
|
|
156
|
-
@asset_tags_group
|
|
157
|
-
@click.option("--type", "asset_type", type=click.Choice(ASSET_TYPES))
|
|
166
|
+
@openapi_command(asset_tags_group, "list", contract("GET", "/api/v1/assets/tags"))
|
|
167
|
+
@click.option("--type", "asset_type", type=click.Choice(ASSET_TYPES), help="只返回指定资源类型使用的标签")
|
|
158
168
|
@click.pass_context
|
|
159
169
|
def list_asset_tags_cmd(ctx: click.Context, asset_type: str | None) -> None:
|
|
160
170
|
"""列出工作空间资源标签。"""
|
|
@@ -166,9 +176,9 @@ def list_asset_tags_cmd(ctx: click.Context, asset_type: str | None) -> None:
|
|
|
166
176
|
handle_api_error("获取资源标签失败", err)
|
|
167
177
|
|
|
168
178
|
|
|
169
|
-
@asset_group
|
|
179
|
+
@openapi_command(asset_group, "update", contract("PATCH", "/api/v1/assets/{asset_id}"))
|
|
170
180
|
@click.argument("asset_id", type=int)
|
|
171
|
-
@click.option("--payload-file", type=click.Path(exists=True, dir_okay=False), required=True)
|
|
181
|
+
@click.option("--payload-file", type=click.Path(exists=True, dir_okay=False), required=True, help="资源元数据更新 JSON 请求体")
|
|
172
182
|
@idempotency_key_option
|
|
173
183
|
@click.pass_context
|
|
174
184
|
def update_asset_cmd(ctx: click.Context, asset_id: int, payload_file: str) -> None:
|
|
@@ -180,9 +190,9 @@ def update_asset_cmd(ctx: click.Context, asset_id: int, payload_file: str) -> No
|
|
|
180
190
|
handle_api_error("更新资源失败", err)
|
|
181
191
|
|
|
182
192
|
|
|
183
|
-
@asset_group
|
|
193
|
+
@openapi_command(asset_group, "copy", contract("POST", "/api/v1/assets/{asset_id}/copy"))
|
|
184
194
|
@click.argument("asset_id", type=int)
|
|
185
|
-
@click.option("--payload-file", type=click.Path(exists=True, dir_okay=False), required=True)
|
|
195
|
+
@click.option("--payload-file", type=click.Path(exists=True, dir_okay=False), required=True, help="资源副本名称、说明等 JSON 请求体")
|
|
186
196
|
@idempotency_key_option
|
|
187
197
|
@click.pass_context
|
|
188
198
|
def copy_asset_cmd(ctx: click.Context, asset_id: int, payload_file: str) -> None:
|
|
@@ -194,14 +204,19 @@ def copy_asset_cmd(ctx: click.Context, asset_id: int, payload_file: str) -> None
|
|
|
194
204
|
handle_api_error("复制资源失败", err)
|
|
195
205
|
|
|
196
206
|
|
|
197
|
-
@
|
|
207
|
+
@openapi_command(
|
|
208
|
+
asset_group,
|
|
209
|
+
"archive",
|
|
210
|
+
contract("POST", "/api/v1/assets/{asset_id}/archive", "提供 ASSET_ID 时"),
|
|
211
|
+
contract("POST", "/api/v1/assets/batch-archive", "提供 --ids-file 时"),
|
|
212
|
+
)
|
|
198
213
|
@click.argument("asset_id", type=int, required=False)
|
|
199
|
-
@click.option("--ids-file", type=click.Path(exists=True, dir_okay=False))
|
|
200
|
-
@click.option("--yes", is_flag=True)
|
|
214
|
+
@click.option("--ids-file", type=click.Path(exists=True, dir_okay=False), help="批量归档的正整数 ID JSON 数组")
|
|
215
|
+
@click.option("--yes", is_flag=True, help="仅在用户已明确授权归档时跳过交互确认")
|
|
201
216
|
@idempotency_key_option
|
|
202
217
|
@click.pass_context
|
|
203
218
|
def archive_asset_cmd(ctx: click.Context, asset_id: int | None, ids_file: str | None, yes: bool) -> None:
|
|
204
|
-
"""
|
|
219
|
+
"""归档单个资源或 JSON 数组指定的一批资源;两种目标输入只能选一种。"""
|
|
205
220
|
|
|
206
221
|
try:
|
|
207
222
|
client = get_client(ctx)
|
|
@@ -6,6 +6,7 @@ import click
|
|
|
6
6
|
|
|
7
7
|
from wp.client import ApiClientError
|
|
8
8
|
from wp.commands.common import get_client, handle_api_error, output_result
|
|
9
|
+
from wp.openapi_help import contract, openapi_command
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
@click.group("runtime-kit")
|
|
@@ -13,13 +14,13 @@ def runtime_kit_group() -> None:
|
|
|
13
14
|
"""Runtime Kit 公开能力目录。"""
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
@runtime_kit_group
|
|
17
|
-
@click.option("--keyword")
|
|
18
|
-
@click.option("--category")
|
|
19
|
-
@click.option("--kind")
|
|
20
|
-
@click.option("--base-name")
|
|
21
|
-
@click.option("--version-no", type=int)
|
|
22
|
-
@click.option("--include-all-versions", is_flag=True)
|
|
17
|
+
@openapi_command(runtime_kit_group, "list", contract("GET", "/api/v1/runtime-kit"))
|
|
18
|
+
@click.option("--keyword", help="按名称、说明或导入路径搜索")
|
|
19
|
+
@click.option("--category", help="按服务端返回的能力分类筛选")
|
|
20
|
+
@click.option("--kind", help="按能力类型筛选,例如 component、composable、util 或 type")
|
|
21
|
+
@click.option("--base-name", help="按不含版本号的能力基础名称筛选")
|
|
22
|
+
@click.option("--version-no", type=int, help="筛选指定公开版本号")
|
|
23
|
+
@click.option("--include-all-versions", is_flag=True, help="返回所有公开版本;默认只返回推荐版本")
|
|
23
24
|
@click.pass_context
|
|
24
25
|
def runtime_kit_list_cmd(
|
|
25
26
|
ctx: click.Context,
|
|
@@ -50,7 +51,7 @@ def runtime_kit_list_cmd(
|
|
|
50
51
|
handle_api_error("获取 Runtime Kit 目录失败", err)
|
|
51
52
|
|
|
52
53
|
|
|
53
|
-
@runtime_kit_group
|
|
54
|
+
@openapi_command(runtime_kit_group, "get", contract("GET", "/api/v1/runtime-kit/{item}"))
|
|
54
55
|
@click.argument("item")
|
|
55
56
|
@click.pass_context
|
|
56
57
|
def runtime_kit_get_cmd(ctx: click.Context, item: str) -> None:
|
|
@@ -67,10 +68,10 @@ def font_group() -> None:
|
|
|
67
68
|
"""工作空间注册字体目录。"""
|
|
68
69
|
|
|
69
70
|
|
|
70
|
-
@font_group
|
|
71
|
-
@click.option("--page", default=1, type=int)
|
|
72
|
-
@click.option("--page-size", default=50, type=int)
|
|
73
|
-
@click.option("--keyword")
|
|
71
|
+
@openapi_command(font_group, "list", contract("GET", "/api/v1/fonts"))
|
|
72
|
+
@click.option("--page", default=1, type=int, show_default=True, help="结果页码")
|
|
73
|
+
@click.option("--page-size", default=50, type=int, show_default=True, help="每页返回数量")
|
|
74
|
+
@click.option("--keyword", help="按字体名称或逻辑名搜索")
|
|
74
75
|
@click.pass_context
|
|
75
76
|
def font_list_cmd(ctx: click.Context, page: int, page_size: int, keyword: str | None) -> None:
|
|
76
77
|
"""查询工作空间注册字体。"""
|
|
@@ -21,6 +21,7 @@ from wp.commands.common import (
|
|
|
21
21
|
)
|
|
22
22
|
from wp.config import get_profile, load_config
|
|
23
23
|
from wp.formatter import print_table
|
|
24
|
+
from wp.openapi_help import contract, openapi_command
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
@click.group("component")
|
|
@@ -28,12 +29,12 @@ def component_group() -> None:
|
|
|
28
29
|
"""工作空间组件管理与 Mutation 任务。"""
|
|
29
30
|
|
|
30
31
|
|
|
31
|
-
@component_group
|
|
32
|
-
@click.option("--page", default=1, type=int)
|
|
33
|
-
@click.option("--page-size", default=50, type=int)
|
|
34
|
-
@click.option("--keyword")
|
|
35
|
-
@click.option("--scope", type=click.Choice(["all", "suggested"]), default="all")
|
|
36
|
-
@click.option("--project-id", type=int)
|
|
32
|
+
@openapi_command(component_group, "list", contract("GET", "/api/v1/components"))
|
|
33
|
+
@click.option("--page", default=1, type=int, show_default=True, help="结果页码")
|
|
34
|
+
@click.option("--page-size", default=50, type=int, show_default=True, help="每页返回数量")
|
|
35
|
+
@click.option("--keyword", help="按名称、导入标识或摘要搜索")
|
|
36
|
+
@click.option("--scope", type=click.Choice(["all", "suggested"]), default="all", show_default=True, help="查询全部组件或指定项目的建议组件")
|
|
37
|
+
@click.option("--project-id", type=int, help="scope=suggested 时必填的项目 ID")
|
|
37
38
|
@click.pass_context
|
|
38
39
|
def list_components_cmd(ctx: click.Context, page: int, page_size: int, keyword: str | None, scope: str, project_id: int | None) -> None:
|
|
39
40
|
"""查询工作空间组件或项目建议组件。"""
|
|
@@ -55,7 +56,7 @@ def list_components_cmd(ctx: click.Context, page: int, page_size: int, keyword:
|
|
|
55
56
|
handle_api_error("获取组件列表失败", err)
|
|
56
57
|
|
|
57
58
|
|
|
58
|
-
@component_group
|
|
59
|
+
@openapi_command(component_group, "get", contract("GET", "/api/v1/components/{component_id}"))
|
|
59
60
|
@click.argument("component_id", type=int)
|
|
60
61
|
@click.pass_context
|
|
61
62
|
def get_component_cmd(ctx: click.Context, component_id: int) -> None:
|
|
@@ -67,16 +68,21 @@ def get_component_cmd(ctx: click.Context, component_id: int) -> None:
|
|
|
67
68
|
handle_api_error("获取组件失败", err)
|
|
68
69
|
|
|
69
70
|
|
|
70
|
-
@
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
@click.option("--
|
|
77
|
-
@click.option("--
|
|
78
|
-
@click.option("--
|
|
79
|
-
@click.option("--
|
|
71
|
+
@openapi_command(
|
|
72
|
+
component_group,
|
|
73
|
+
"create",
|
|
74
|
+
contract("POST", "/api/v1/components"),
|
|
75
|
+
examples=('wp component create --name "指标卡" --import-name MetricCard --file ./MetricCard.vue --type content --idempotency-key component-metric-card',),
|
|
76
|
+
)
|
|
77
|
+
@click.option("--name", help="组件显示名称;直接参数模式必填")
|
|
78
|
+
@click.option("--import-name", help="稳定导入标识;直接参数模式必填")
|
|
79
|
+
@click.option("--file", "file_path", type=click.Path(exists=True, dir_okay=False), help="完整 Vue 3 SFC 文件;直接参数模式必填")
|
|
80
|
+
@click.option("--type", "component_type", default="content", show_default=True, help="组件类型:content、page、atomic 或服务端兼容别名")
|
|
81
|
+
@click.option("--description", help="组件用途和复用边界说明")
|
|
82
|
+
@click.option("--preview-schema-file", type=click.Path(exists=True, dir_okay=False), help="覆盖请求体 preview_schema 的 JSON 对象")
|
|
83
|
+
@click.option("--payload-file", type=click.Path(exists=True, dir_okay=False), help="完整组件创建 JSON 请求体;提供后忽略其它内容参数")
|
|
84
|
+
@click.option("--wait/--no-wait", default=True, help="等待任务终态;--no-wait 只返回入队结果")
|
|
85
|
+
@click.option("--timeout", type=float, default=120.0, show_default=True, help="等待任务终态的最长秒数")
|
|
80
86
|
@idempotency_key_option
|
|
81
87
|
@click.pass_context
|
|
82
88
|
def create_component_cmd(
|
|
@@ -91,7 +97,7 @@ def create_component_cmd(
|
|
|
91
97
|
wait: bool,
|
|
92
98
|
timeout: float,
|
|
93
99
|
) -> None:
|
|
94
|
-
"""提交组件创建 Mutation Job。"""
|
|
100
|
+
"""提交组件创建 Mutation Job;直接参数模式必须提供名称、导入标识和完整 SFC。"""
|
|
95
101
|
|
|
96
102
|
profile = get_profile(load_config(), ctx.obj.get("profile"))
|
|
97
103
|
workspace_id = ctx.obj.get("workspace_id") or profile.default_workspace_id
|
|
@@ -122,12 +128,18 @@ def create_component_cmd(
|
|
|
122
128
|
handle_api_error("提交组件创建失败", err)
|
|
123
129
|
|
|
124
130
|
|
|
125
|
-
@
|
|
131
|
+
@openapi_command(
|
|
132
|
+
component_group,
|
|
133
|
+
"update",
|
|
134
|
+
contract("PATCH", "/api/v1/components/{component_id}", "仅更新 name 或 summary 时"),
|
|
135
|
+
contract("POST", "/api/v1/jobs/mutations/components/metadata", "包含 import_name、component_type 或 preview_schema 时"),
|
|
136
|
+
examples=("wp component update 15 --payload-file ./component-update.json --idempotency-key component-15-metadata",),
|
|
137
|
+
)
|
|
126
138
|
@click.argument("component_id", type=int)
|
|
127
|
-
@click.option("--payload-file", type=click.Path(exists=True, dir_okay=False), required=True)
|
|
139
|
+
@click.option("--payload-file", type=click.Path(exists=True, dir_okay=False), required=True, help="组件元数据 JSON 请求体;复杂字段会自动进入异步任务")
|
|
128
140
|
@click.option("--preview-schema-file", type=click.Path(exists=True, dir_okay=False), help="覆盖 payload 中的 Preview Schema JSON")
|
|
129
|
-
@click.option("--wait/--no-wait", default=True)
|
|
130
|
-
@click.option("--timeout", type=float, default=120.0, show_default=True)
|
|
141
|
+
@click.option("--wait/--no-wait", default=True, help="复杂字段更新时等待任务终态;轻量更新忽略此选项")
|
|
142
|
+
@click.option("--timeout", type=float, default=120.0, show_default=True, help="等待复杂字段更新任务的最长秒数")
|
|
131
143
|
@idempotency_key_option
|
|
132
144
|
@click.pass_context
|
|
133
145
|
def update_component_cmd(
|
|
@@ -160,13 +172,18 @@ def update_component_cmd(
|
|
|
160
172
|
handle_api_error("更新组件失败", err)
|
|
161
173
|
|
|
162
174
|
|
|
163
|
-
@
|
|
175
|
+
@openapi_command(
|
|
176
|
+
component_group,
|
|
177
|
+
"edit",
|
|
178
|
+
contract("POST", "/api/v1/components/{component_id}/edits"),
|
|
179
|
+
examples=("wp component edit 15 --base-version-no 2 --base-draft-hash <hash> --edits-file ./edits.json --idempotency-key component-15-edit",),
|
|
180
|
+
)
|
|
164
181
|
@click.argument("component_id", type=int)
|
|
165
|
-
@click.option("--edits-file", type=click.Path(exists=True, dir_okay=False), required=True)
|
|
166
|
-
@click.option("--base-version-no", type=int, required=True)
|
|
167
|
-
@click.option("--base-draft-hash", required=True)
|
|
168
|
-
@click.option("--wait/--no-wait", default=True)
|
|
169
|
-
@click.option("--timeout", type=float, default=120.0, show_default=True)
|
|
182
|
+
@click.option("--edits-file", type=click.Path(exists=True, dir_okay=False), required=True, help="结构化编辑 JSON 数组;完整字段以当前 OpenAPI Schema 为准")
|
|
183
|
+
@click.option("--base-version-no", type=int, required=True, help="component get 返回的最新发布版本基线")
|
|
184
|
+
@click.option("--base-draft-hash", required=True, help="component get 返回的最新草稿哈希基线")
|
|
185
|
+
@click.option("--wait/--no-wait", default=True, help="等待任务终态;--no-wait 只返回入队结果")
|
|
186
|
+
@click.option("--timeout", type=float, default=120.0, show_default=True, help="等待任务终态的最长秒数")
|
|
170
187
|
@idempotency_key_option
|
|
171
188
|
@click.pass_context
|
|
172
189
|
def edit_component_cmd(ctx: click.Context, component_id: int, edits_file: str, base_version_no: int, base_draft_hash: str, wait: bool, timeout: float) -> None:
|
|
@@ -189,7 +206,7 @@ def component_version_group() -> None:
|
|
|
189
206
|
"""组件历史发布版本。"""
|
|
190
207
|
|
|
191
208
|
|
|
192
|
-
@component_version_group
|
|
209
|
+
@openapi_command(component_version_group, "list", contract("GET", "/api/v1/components/{component_id}/versions"))
|
|
193
210
|
@click.argument("component_id", type=int)
|
|
194
211
|
@click.pass_context
|
|
195
212
|
def list_component_versions_cmd(ctx: click.Context, component_id: int) -> None:
|
|
@@ -201,7 +218,7 @@ def list_component_versions_cmd(ctx: click.Context, component_id: int) -> None:
|
|
|
201
218
|
handle_api_error("获取组件版本失败", err)
|
|
202
219
|
|
|
203
220
|
|
|
204
|
-
@component_version_group
|
|
221
|
+
@openapi_command(component_version_group, "get", contract("GET", "/api/v1/components/{component_id}/versions/{version_no}"))
|
|
205
222
|
@click.argument("component_id", type=int)
|
|
206
223
|
@click.argument("version_no", type=int)
|
|
207
224
|
@click.pass_context
|
|
@@ -214,7 +231,7 @@ def get_component_version_cmd(ctx: click.Context, component_id: int, version_no:
|
|
|
214
231
|
handle_api_error("获取组件版本内容失败", err)
|
|
215
232
|
|
|
216
233
|
|
|
217
|
-
@component_group
|
|
234
|
+
@openapi_command(component_group, "dependencies", contract("GET", "/api/v1/components/{component_id}/dependencies"))
|
|
218
235
|
@click.argument("component_id", type=int)
|
|
219
236
|
@click.pass_context
|
|
220
237
|
def component_dependencies_cmd(ctx: click.Context, component_id: int) -> None:
|
|
@@ -226,13 +243,18 @@ def component_dependencies_cmd(ctx: click.Context, component_id: int) -> None:
|
|
|
226
243
|
handle_api_error("获取组件依赖失败", err)
|
|
227
244
|
|
|
228
245
|
|
|
229
|
-
@
|
|
246
|
+
@openapi_command(
|
|
247
|
+
component_group,
|
|
248
|
+
"validate",
|
|
249
|
+
contract("POST", "/api/v1/validate/entity"),
|
|
250
|
+
examples=("wp --json component validate 15 --mode content --source-file ./MetricCard.vue --detail",),
|
|
251
|
+
)
|
|
230
252
|
@click.argument("component_id", type=int)
|
|
231
|
-
@click.option("--mode", type=click.Choice(["current", "content", "edits"]), default="current")
|
|
232
|
-
@click.option("--source-file", type=click.Path(exists=True, dir_okay=False))
|
|
233
|
-
@click.option("--edits-file", type=click.Path(exists=True, dir_okay=False))
|
|
234
|
-
@click.option("--preview-schema-file", type=click.Path(exists=True, dir_okay=False))
|
|
235
|
-
@click.option("--detail", is_flag=True)
|
|
253
|
+
@click.option("--mode", type=click.Choice(["current", "content", "edits"]), default="current", show_default=True, help="校验当前草稿、完整候选源码或结构化 edits")
|
|
254
|
+
@click.option("--source-file", type=click.Path(exists=True, dir_okay=False), help="content 模式必填的完整候选 SFC")
|
|
255
|
+
@click.option("--edits-file", type=click.Path(exists=True, dir_okay=False), help="edits 模式必填的结构化编辑 JSON 数组")
|
|
256
|
+
@click.option("--preview-schema-file", type=click.Path(exists=True, dir_okay=False), help="可选的候选 preview_schema JSON 对象")
|
|
257
|
+
@click.option("--detail", is_flag=True, help="返回完整编译、渲染和布局诊断")
|
|
236
258
|
@click.pass_context
|
|
237
259
|
def validate_component_cmd(ctx: click.Context, component_id: int, mode: str, source_file: str | None, edits_file: str | None, preview_schema_file: str | None, detail: bool) -> None:
|
|
238
260
|
"""校验组件当前或候选源码。"""
|
|
@@ -254,10 +276,10 @@ def validate_component_cmd(ctx: click.Context, component_id: int, mode: str, sou
|
|
|
254
276
|
handle_api_error("组件校验失败", err)
|
|
255
277
|
|
|
256
278
|
|
|
257
|
-
@component_group
|
|
279
|
+
@openapi_command(component_group, "publish", contract("POST", "/api/v1/components/{component_id}/publish"))
|
|
258
280
|
@click.argument("component_id", type=int)
|
|
259
|
-
@click.option("--release-name")
|
|
260
|
-
@click.option("--change-note")
|
|
281
|
+
@click.option("--release-name", help="本次发布版本的可读名称")
|
|
282
|
+
@click.option("--change-note", help="本次发布的变更说明")
|
|
261
283
|
@idempotency_key_option
|
|
262
284
|
@click.pass_context
|
|
263
285
|
def publish_component_cmd(ctx: click.Context, component_id: int, release_name: str | None, change_note: str | None) -> None:
|
|
@@ -269,14 +291,19 @@ def publish_component_cmd(ctx: click.Context, component_id: int, release_name: s
|
|
|
269
291
|
handle_api_error("发布组件失败", err)
|
|
270
292
|
|
|
271
293
|
|
|
272
|
-
@
|
|
294
|
+
@openapi_command(
|
|
295
|
+
component_group,
|
|
296
|
+
"archive",
|
|
297
|
+
contract("POST", "/api/v1/components/{component_id}/archive", "提供 COMPONENT_ID 时"),
|
|
298
|
+
contract("POST", "/api/v1/components/batch-archive", "提供 --ids-file 时"),
|
|
299
|
+
)
|
|
273
300
|
@click.argument("component_id", type=int, required=False)
|
|
274
|
-
@click.option("--ids-file", type=click.Path(exists=True, dir_okay=False))
|
|
275
|
-
@click.option("--yes", is_flag=True)
|
|
301
|
+
@click.option("--ids-file", type=click.Path(exists=True, dir_okay=False), help="批量归档的正整数 ID JSON 数组")
|
|
302
|
+
@click.option("--yes", is_flag=True, help="仅在用户已明确授权归档时跳过交互确认")
|
|
276
303
|
@idempotency_key_option
|
|
277
304
|
@click.pass_context
|
|
278
305
|
def archive_component_cmd(ctx: click.Context, component_id: int | None, ids_file: str | None, yes: bool) -> None:
|
|
279
|
-
"""
|
|
306
|
+
"""归档单个组件或 JSON 数组指定的一批组件;两种目标输入只能选一种。"""
|
|
280
307
|
|
|
281
308
|
try:
|
|
282
309
|
client = get_client(ctx)
|
|
@@ -12,6 +12,7 @@ from wp.commands.common import (
|
|
|
12
12
|
output_result,
|
|
13
13
|
require_success_job,
|
|
14
14
|
)
|
|
15
|
+
from wp.openapi_help import contract, openapi_command
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
@click.group("job")
|
|
@@ -19,7 +20,7 @@ def job_group() -> None:
|
|
|
19
20
|
"""异步任务管理。"""
|
|
20
21
|
|
|
21
22
|
|
|
22
|
-
@job_group
|
|
23
|
+
@openapi_command(job_group, "get", contract("GET", "/api/v1/jobs/mutations/{job_id}"))
|
|
23
24
|
@click.argument("job_id")
|
|
24
25
|
@click.pass_context
|
|
25
26
|
def get_job_cmd(ctx: click.Context, job_id: str) -> None:
|
|
@@ -31,9 +32,14 @@ def get_job_cmd(ctx: click.Context, job_id: str) -> None:
|
|
|
31
32
|
handle_api_error("查询 Job 失败", err)
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
@
|
|
35
|
+
@openapi_command(
|
|
36
|
+
job_group,
|
|
37
|
+
"wait",
|
|
38
|
+
contract("GET", "/api/v1/jobs/mutations/{job_id}"),
|
|
39
|
+
examples=("wp --json job wait <job_id> --timeout 120",),
|
|
40
|
+
)
|
|
35
41
|
@click.argument("job_id")
|
|
36
|
-
@click.option("--timeout", default=120.0, type=float, show_default=True)
|
|
42
|
+
@click.option("--timeout", default=120.0, type=float, show_default=True, help="等待终态的最长秒数")
|
|
37
43
|
@click.pass_context
|
|
38
44
|
def wait_job_cmd(ctx: click.Context, job_id: str, timeout: float) -> None:
|
|
39
45
|
"""等待 Mutation Job 进入终态。"""
|
|
@@ -46,7 +52,7 @@ def wait_job_cmd(ctx: click.Context, job_id: str, timeout: float) -> None:
|
|
|
46
52
|
handle_api_error("等待 Job 失败", err)
|
|
47
53
|
|
|
48
54
|
|
|
49
|
-
@job_group
|
|
55
|
+
@openapi_command(job_group, "cancel", contract("POST", "/api/v1/jobs/mutations/{job_id}/cancel"))
|
|
50
56
|
@click.argument("job_id")
|
|
51
57
|
@idempotency_key_option
|
|
52
58
|
@click.pass_context
|
|
@@ -65,7 +71,7 @@ def cancel_job_cmd(ctx: click.Context, job_id: str) -> None:
|
|
|
65
71
|
handle_api_error("取消 Job 失败", err)
|
|
66
72
|
|
|
67
73
|
|
|
68
|
-
@job_group
|
|
74
|
+
@openapi_command(job_group, "retry", contract("POST", "/api/v1/jobs/mutations/{job_id}/retry"))
|
|
69
75
|
@click.argument("job_id")
|
|
70
76
|
@idempotency_key_option
|
|
71
77
|
@click.pass_context
|