@josephyan/qingflow-cli 1.0.11 → 1.1.2
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.
- package/README.md +3 -3
- package/npm/bin/qingflow.mjs +40 -2
- package/npm/lib/runtime.mjs +386 -15
- package/npm/scripts/postinstall.mjs +7 -2
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-cli/SKILL.md +440 -0
- package/skills/qingflow-cli/manifest.yaml +10 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_ADMIN_CHEATSHEET.md +94 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_APP_DELIVERY_WORKFLOW.md +485 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_CHARTS_WORKFLOW.md +237 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_MATCH_RULES.md +137 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_PORTAL_WORKFLOW.md +263 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_VIEWS_WORKFLOW.md +304 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_BUILDER_WORKSPACE_ICONS.md +41 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_DATA_RETRIEVAL_WORKFLOW.md +139 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_EXPLORATION_REPORT.md +84 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_FIELD_DATA_TYPES.md +129 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_MEMBER_CHEATSHEET.md +195 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_ONE_SHOT_CHEATSHEET.md +159 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_RECORD_CREATE_WORKFLOW.md +20 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_RECORD_IMPORT_WORKFLOW.md +176 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_RECORD_UPDATE_WORKFLOW.md +163 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_SCHEMA_APPLY_FIELD_TYPES_AND_SCENARIOS.md +107 -0
- package/skills/qingflow-cli/reference/QINGFLOW_CLI_TASK_CONTEXT_WORKFLOW.md +151 -0
- package/skills/qingflow-cli/reference/_batch_schema_complex.json +18 -0
- package/skills/qingflow-cli/reference/_batch_schema_scalar.json +17 -0
- package/skills/qingflow-cli/reference/charts_remove.example.json +1 -0
- package/skills/qingflow-cli/reference/charts_reorder.example.json +1 -0
- package/skills/qingflow-cli/reference/charts_upsert_bar.example.json +8 -0
- package/skills/qingflow-cli/reference/charts_upsert_dashboard_starter.example.json +37 -0
- package/skills/qingflow-cli/reference/charts_upsert_minimal.example.json +13 -0
- package/skills/qingflow-cli/reference/portal_sections_all_types.example.json +131 -0
- package/skills/qingflow-cli/reference/portal_sections_five_types.example.json +126 -0
- package/skills/qingflow-cli/reference/portal_sections_standard_workbench.example.json +128 -0
- package/skills/qingflow-cli/reference/schema_add_fields_minimal.example.json +7 -0
- package/skills/qingflow-cli/reference/schema_apply_add_fields_all_types.json +78 -0
- package/skills/qingflow-cli/reference/views_upsert_table_minimal.example.json +7 -0
- package/skills/qingflow-cli/scripts/builder-package-from-app-list.py +140 -0
- package/skills/qingflow-cli/scripts/find-app-by-keyword.py +132 -0
- package/skills/qingflow-cli/scripts/validate_qingflow_output_files.py +87 -0
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/builder_facade/models.py +532 -48
- package/src/qingflow_mcp/builder_facade/service.py +9194 -2384
- package/src/qingflow_mcp/builder_facade/workflow_spec.py +111 -0
- package/src/qingflow_mcp/cli/commands/app.py +3 -16
- package/src/qingflow_mcp/cli/commands/builder.py +354 -56
- package/src/qingflow_mcp/cli/commands/record.py +89 -2
- package/src/qingflow_mcp/cli/formatters.py +32 -1
- package/src/qingflow_mcp/cli/main.py +245 -3
- package/src/qingflow_mcp/public_surface.py +11 -8
- package/src/qingflow_mcp/response_trim.py +143 -14
- package/src/qingflow_mcp/server.py +15 -12
- package/src/qingflow_mcp/server_app_builder.py +108 -30
- package/src/qingflow_mcp/server_app_user.py +17 -18
- package/src/qingflow_mcp/solution/compiler/__init__.py +1 -3
- package/src/qingflow_mcp/solution/compiler/icon_utils.py +294 -0
- package/src/qingflow_mcp/solution/executor.py +3 -133
- package/src/qingflow_mcp/tools/ai_builder_tools.py +2617 -440
- package/src/qingflow_mcp/tools/app_tools.py +53 -8
- package/src/qingflow_mcp/tools/package_tools.py +16 -2
- package/src/qingflow_mcp/tools/record_tools.py +2095 -176
- package/src/qingflow_mcp/tools/resource_read_tools.py +3 -0
- package/src/qingflow_mcp/tools/solution_tools.py +30 -2
- package/src/qingflow_mcp/tools/workflow_tools.py +3 -31
- package/src/qingflow_mcp/version.py +110 -0
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +0 -173
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
+
from typing import Any
|
|
4
5
|
|
|
5
6
|
from ..context import CliContext
|
|
6
7
|
from .common import load_list_arg, load_object_arg, raise_config_error, require_list_arg
|
|
7
8
|
|
|
8
9
|
|
|
10
|
+
def _parse_app_keys_arg(raw: Any) -> list[str] | None:
|
|
11
|
+
"""Parse comma-separated --app-keys argument into a list, or return None if empty."""
|
|
12
|
+
if not raw:
|
|
13
|
+
return None
|
|
14
|
+
keys = [k.strip() for k in str(raw).split(",") if k.strip()]
|
|
15
|
+
return keys if keys else None
|
|
16
|
+
|
|
17
|
+
|
|
9
18
|
def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
|
|
10
19
|
parser = subparsers.add_parser("builder", aliases=["build"], help="稳定 builder 命令")
|
|
11
20
|
builder_subparsers = parser.add_subparsers(dest="builder_command", required=True)
|
|
@@ -42,6 +51,11 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
42
51
|
contract.add_argument("--tool-name", required=True)
|
|
43
52
|
contract.set_defaults(handler=_handle_contract, format_hint="builder_summary")
|
|
44
53
|
|
|
54
|
+
icon = builder_subparsers.add_parser("icon", help="工作区图标目录")
|
|
55
|
+
icon_subparsers = icon.add_subparsers(dest="builder_icon_command", required=True)
|
|
56
|
+
icon_catalog = icon_subparsers.add_parser("catalog", help="读取应用、应用包、门户可用图标目录")
|
|
57
|
+
icon_catalog.set_defaults(handler=_handle_icon_catalog, format_hint="builder_summary")
|
|
58
|
+
|
|
45
59
|
member = builder_subparsers.add_parser("member", help="成员目录")
|
|
46
60
|
member_subparsers = member.add_subparsers(dest="builder_member_command", required=True)
|
|
47
61
|
member_search = member_subparsers.add_parser("search", help="搜索成员")
|
|
@@ -78,13 +92,18 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
78
92
|
solution_install.add_argument("--solution-source", default="solutionDetail")
|
|
79
93
|
solution_install.set_defaults(handler=_handle_solution_install, format_hint="builder_summary")
|
|
80
94
|
|
|
95
|
+
package_list = package_subparsers.add_parser("list", help="列出应用包")
|
|
96
|
+
package_list.add_argument("--trial-status", default="all")
|
|
97
|
+
package_list.add_argument("--query", default="")
|
|
98
|
+
package_list.set_defaults(handler=_handle_package_list, format_hint="builder_summary")
|
|
99
|
+
|
|
81
100
|
package_get = package_subparsers.add_parser("get", help="读取应用包详情")
|
|
82
101
|
package_get.add_argument("--package-id", type=int, required=True)
|
|
83
102
|
package_get.set_defaults(handler=_handle_package_get, format_hint="builder_summary")
|
|
84
103
|
|
|
85
104
|
package_apply = package_subparsers.add_parser("apply", help="创建或更新应用包配置")
|
|
86
105
|
package_apply.add_argument("--config-file", required=True)
|
|
87
|
-
package_apply.set_defaults(handler=_handle_package_apply, format_hint="builder_summary")
|
|
106
|
+
package_apply.set_defaults(handler=_handle_package_apply, format_hint="builder_summary", force_json_output=True)
|
|
88
107
|
|
|
89
108
|
app = builder_subparsers.add_parser("app", help="应用")
|
|
90
109
|
app_subparsers = app.add_subparsers(dest="builder_app_command", required=True)
|
|
@@ -99,16 +118,17 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
99
118
|
app_release_lock.add_argument("--app-key", required=True)
|
|
100
119
|
app_release_lock.add_argument("--lock-owner-email", required=True)
|
|
101
120
|
app_release_lock.add_argument("--lock-owner-name", required=True)
|
|
102
|
-
app_release_lock.set_defaults(handler=_handle_app_release_edit_lock_if_mine, format_hint="builder_summary")
|
|
121
|
+
app_release_lock.set_defaults(handler=_handle_app_release_edit_lock_if_mine, format_hint="builder_summary", force_json_output=True)
|
|
103
122
|
|
|
104
123
|
app_get = app_subparsers.add_parser("get", help="读取应用配置(字段请使用: builder app get --app-key APP fields)")
|
|
105
124
|
app_get.add_argument(
|
|
106
125
|
"builder_app_get_section",
|
|
107
126
|
nargs="?",
|
|
108
|
-
choices=["summary", "fields", "layout", "views", "flow", "charts"],
|
|
127
|
+
choices=["summary", "fields", "layout", "views", "flow", "charts", "buttons", "associated-resources"],
|
|
109
128
|
default="summary",
|
|
110
129
|
)
|
|
111
|
-
app_get.add_argument("--app-key",
|
|
130
|
+
app_get.add_argument("--app-key", default="")
|
|
131
|
+
app_get.add_argument("--app-keys", help="逗号分隔的多应用批量读取,例如: KEY1,KEY2,KEY3")
|
|
112
132
|
app_get.set_defaults(handler=_handle_app_get, format_hint="builder_summary")
|
|
113
133
|
|
|
114
134
|
app_repair_code_blocks = app_subparsers.add_parser("repair-code-blocks", help="扫描或修复现有代码块配置")
|
|
@@ -123,30 +143,36 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
123
143
|
button_catalog = button_subparsers.add_parser("catalog", help="读取按钮样式目录")
|
|
124
144
|
button_catalog.set_defaults(handler=_handle_button_catalog, format_hint="builder_summary")
|
|
125
145
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
button_get = button_subparsers.add_parser("get", help="读取自定义按钮")
|
|
131
|
-
button_get.add_argument("--app-key", required=True)
|
|
132
|
-
button_get.add_argument("--button-id", type=int, required=True)
|
|
146
|
+
button_get = button_subparsers.add_parser("get", help="读取应用自定义按钮配置")
|
|
147
|
+
button_get.add_argument("--app-key", default="")
|
|
148
|
+
button_get.add_argument("--app-keys", help="逗号分隔的多应用批量读取,例如: KEY1,KEY2,KEY3")
|
|
133
149
|
button_get.set_defaults(handler=_handle_button_get, format_hint="builder_summary")
|
|
134
150
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
button_apply = button_subparsers.add_parser("apply", help="声明式创建、更新或删除自定义按钮")
|
|
152
|
+
button_apply.add_argument("--app-key", default="")
|
|
153
|
+
button_apply.add_argument("--upsert-buttons-file")
|
|
154
|
+
button_apply.add_argument("--patch-buttons-file")
|
|
155
|
+
button_apply.add_argument("--remove-buttons-file")
|
|
156
|
+
button_apply.add_argument("--view-configs-file")
|
|
157
|
+
button_apply.add_argument("--apps-file", help="多应用批量按钮 JSON 数组,每项含 app_key + upsert_buttons/patch_buttons/remove_buttons/view_configs")
|
|
158
|
+
button_apply.set_defaults(handler=_handle_button_apply, format_hint="builder_summary", force_json_output=True)
|
|
159
|
+
|
|
160
|
+
associated_resource = builder_subparsers.add_parser("associated-resource", aliases=["associated-resources"], help="关联视图/报表")
|
|
161
|
+
associated_resource_subparsers = associated_resource.add_subparsers(dest="builder_associated_resource_command", required=True)
|
|
162
|
+
|
|
163
|
+
associated_resource_get = associated_resource_subparsers.add_parser("get", help="读取应用关联资源配置")
|
|
164
|
+
associated_resource_get.add_argument("--app-key", default="")
|
|
165
|
+
associated_resource_get.add_argument("--app-keys", help="逗号分隔的多应用批量读取,例如: KEY1,KEY2,KEY3")
|
|
166
|
+
associated_resource_get.set_defaults(handler=_handle_associated_resource_get, format_hint="builder_summary")
|
|
167
|
+
|
|
168
|
+
associated_resource_apply = associated_resource_subparsers.add_parser("apply", help="声明式管理应用关联资源池和视图展示配置")
|
|
169
|
+
associated_resource_apply.add_argument("--app-key", required=True)
|
|
170
|
+
associated_resource_apply.add_argument("--upsert-resources-file")
|
|
171
|
+
associated_resource_apply.add_argument("--patch-resources-file")
|
|
172
|
+
associated_resource_apply.add_argument("--remove-associated-item-ids-file")
|
|
173
|
+
associated_resource_apply.add_argument("--reorder-associated-item-ids-file")
|
|
174
|
+
associated_resource_apply.add_argument("--view-configs-file")
|
|
175
|
+
associated_resource_apply.set_defaults(handler=_handle_associated_resource_apply, format_hint="builder_summary", force_json_output=True)
|
|
150
176
|
|
|
151
177
|
portal = builder_subparsers.add_parser("portal", help="门户")
|
|
152
178
|
portal_subparsers = portal.add_subparsers(dest="builder_portal_command", required=True)
|
|
@@ -163,7 +189,9 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
163
189
|
portal_apply.add_argument("--dash-name", default="")
|
|
164
190
|
portal_apply.add_argument("--package-id", type=int)
|
|
165
191
|
portal_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
|
|
192
|
+
portal_apply.add_argument("--payload-file")
|
|
166
193
|
portal_apply.add_argument("--sections-file")
|
|
194
|
+
portal_apply.add_argument("--layout-preset", default="")
|
|
167
195
|
portal_apply.add_argument("--visibility-file")
|
|
168
196
|
portal_apply.add_argument("--auth-file")
|
|
169
197
|
portal_apply.add_argument("--icon")
|
|
@@ -171,7 +199,8 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
171
199
|
portal_apply.add_argument("--hide-copyright", action=argparse.BooleanOptionalAction, default=None)
|
|
172
200
|
portal_apply.add_argument("--dash-global-config-file")
|
|
173
201
|
portal_apply.add_argument("--config-file")
|
|
174
|
-
portal_apply.
|
|
202
|
+
portal_apply.add_argument("--patch-sections-file", help="门户组件局部更新 JSON 数组,每项含 chart_ref/view_ref/order + set/unset")
|
|
203
|
+
portal_apply.set_defaults(handler=_handle_portal_apply, format_hint="builder_summary", force_json_output=True)
|
|
175
204
|
|
|
176
205
|
schema_apply = builder_subparsers.add_parser("schema", help="字段搭建")
|
|
177
206
|
schema_apply_subparsers = schema_apply.add_subparsers(dest="builder_schema_command", required=True)
|
|
@@ -185,54 +214,72 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
|
|
|
185
214
|
schema_apply_apply.add_argument("--visibility-file")
|
|
186
215
|
schema_apply_apply.add_argument("--create-if-missing", action="store_true")
|
|
187
216
|
schema_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
|
|
188
|
-
schema_apply_apply.add_argument("--
|
|
189
|
-
schema_apply_apply.add_argument("--
|
|
217
|
+
schema_apply_apply.add_argument("--apps-file", help="多应用 schema JSON 数组;每项可带 client_key/app_name/add_fields,支持 relation target_app_ref")
|
|
218
|
+
schema_apply_apply.add_argument("--add-fields-file", help="字段 JSON 数组;字段可用 as_data_title/as_data_cover 标记数据标题/封面")
|
|
219
|
+
schema_apply_apply.add_argument("--update-fields-file", help="字段更新 JSON 数组;set 内可用 as_data_title/as_data_cover 标记数据标题/封面")
|
|
190
220
|
schema_apply_apply.add_argument("--remove-fields-file")
|
|
191
|
-
schema_apply_apply.set_defaults(handler=_handle_schema_apply, format_hint="builder_summary")
|
|
221
|
+
schema_apply_apply.set_defaults(handler=_handle_schema_apply, format_hint="builder_summary", force_json_output=True)
|
|
192
222
|
|
|
193
223
|
layout_apply = builder_subparsers.add_parser("layout", help="布局")
|
|
194
224
|
layout_apply_subparsers = layout_apply.add_subparsers(dest="builder_layout_command", required=True)
|
|
195
225
|
layout_apply_apply = layout_apply_subparsers.add_parser("apply", help="执行布局变更")
|
|
196
|
-
layout_apply_apply.add_argument("--app-key",
|
|
226
|
+
layout_apply_apply.add_argument("--app-key", default="")
|
|
197
227
|
layout_apply_apply.add_argument("--mode", choices=["merge", "replace"], default="merge")
|
|
198
228
|
layout_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
|
|
199
|
-
layout_apply_apply.add_argument("--sections-file"
|
|
200
|
-
layout_apply_apply.
|
|
229
|
+
layout_apply_apply.add_argument("--sections-file")
|
|
230
|
+
layout_apply_apply.add_argument("--apps-file", help="多应用批量布局 JSON 数组,每项含 app_key + sections")
|
|
231
|
+
layout_apply_apply.set_defaults(handler=_handle_layout_apply, format_hint="builder_summary", force_json_output=True)
|
|
201
232
|
|
|
202
233
|
views_apply = builder_subparsers.add_parser("views", help="视图")
|
|
203
234
|
views_apply_subparsers = views_apply.add_subparsers(dest="builder_views_command", required=True)
|
|
204
235
|
views_apply_apply = views_apply_subparsers.add_parser("apply", help="执行视图变更")
|
|
205
|
-
views_apply_apply.add_argument("--app-key",
|
|
236
|
+
views_apply_apply.add_argument("--app-key", default="")
|
|
206
237
|
views_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
|
|
207
238
|
views_apply_apply.add_argument("--upsert-views-file")
|
|
239
|
+
views_apply_apply.add_argument("--patch-views-file")
|
|
208
240
|
views_apply_apply.add_argument("--remove-views-file")
|
|
209
|
-
views_apply_apply.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
241
|
+
views_apply_apply.add_argument("--apps-file", help="多应用批量视图 JSON 数组,每项含 app_key + upsert_views/patch_views/remove_views")
|
|
242
|
+
views_apply_apply.set_defaults(handler=_handle_views_apply, format_hint="builder_summary", force_json_output=True)
|
|
243
|
+
|
|
244
|
+
flow_parser = builder_subparsers.add_parser("flow", help="流程(WorkflowSpec)")
|
|
245
|
+
flow_subparsers = flow_parser.add_subparsers(dest="builder_flow_command", required=True)
|
|
246
|
+
|
|
247
|
+
flow_schema = flow_subparsers.add_parser("schema", help="读取 WorkflowSpec JSON Schema")
|
|
248
|
+
flow_schema.add_argument("--schema-version", default="")
|
|
249
|
+
flow_schema.set_defaults(handler=_handle_flow_schema, format_hint="builder_summary")
|
|
250
|
+
|
|
251
|
+
flow_get = flow_subparsers.add_parser("get", help="读取 WorkflowSpec")
|
|
252
|
+
flow_get.add_argument("--app-key", required=True)
|
|
253
|
+
flow_get.add_argument("--version-id", default="")
|
|
254
|
+
flow_get.set_defaults(handler=_handle_flow_get, format_hint="builder_summary")
|
|
255
|
+
|
|
256
|
+
flow_apply = flow_subparsers.add_parser("apply", help="应用 WorkflowSpec")
|
|
257
|
+
flow_apply.add_argument("--app-key", required=True)
|
|
258
|
+
flow_apply.add_argument("--spec-file")
|
|
259
|
+
flow_apply.add_argument("--patch-nodes-file", help="节点局部更新 JSON 数组,每项含 id + set/unset")
|
|
260
|
+
flow_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
|
|
261
|
+
flow_apply.add_argument("--idempotency-key", default="")
|
|
262
|
+
flow_apply.add_argument("--schema-version", default="")
|
|
263
|
+
flow_apply.set_defaults(handler=_handle_flow_apply, format_hint="builder_summary", force_json_output=True)
|
|
220
264
|
|
|
221
265
|
charts_apply = builder_subparsers.add_parser("charts", help="报表")
|
|
222
266
|
charts_apply_subparsers = charts_apply.add_subparsers(dest="builder_charts_command", required=True)
|
|
223
267
|
charts_apply_apply = charts_apply_subparsers.add_parser("apply", help="执行报表变更")
|
|
224
|
-
charts_apply_apply.add_argument("--app-key",
|
|
268
|
+
charts_apply_apply.add_argument("--app-key", default="")
|
|
225
269
|
charts_apply_apply.add_argument("--upsert-file")
|
|
270
|
+
charts_apply_apply.add_argument("--patch-file")
|
|
226
271
|
charts_apply_apply.add_argument("--remove-chart-ids-file")
|
|
227
272
|
charts_apply_apply.add_argument("--reorder-chart-ids-file")
|
|
228
|
-
charts_apply_apply.
|
|
273
|
+
charts_apply_apply.add_argument("--apps-file", help="多应用批量报表 JSON 数组,每项含 app_key + upsert_charts/patch_charts/remove_chart_ids/reorder_chart_ids")
|
|
274
|
+
charts_apply_apply.set_defaults(handler=_handle_charts_apply, format_hint="builder_summary", force_json_output=True)
|
|
229
275
|
|
|
230
276
|
publish_verify = builder_subparsers.add_parser("publish", help="发布校验")
|
|
231
277
|
publish_verify_subparsers = publish_verify.add_subparsers(dest="builder_publish_command", required=True)
|
|
232
278
|
publish_verify_verify = publish_verify_subparsers.add_parser("verify", help="校验应用发布")
|
|
233
|
-
publish_verify_verify.add_argument("--app-key",
|
|
279
|
+
publish_verify_verify.add_argument("--app-key", default="")
|
|
280
|
+
publish_verify_verify.add_argument("--app-keys", help="逗号分隔的多应用批量校验,例如: KEY1,KEY2,KEY3")
|
|
234
281
|
publish_verify_verify.add_argument("--expected-package-id", type=int)
|
|
235
|
-
publish_verify_verify.set_defaults(handler=_handle_publish_verify, format_hint="builder_summary")
|
|
282
|
+
publish_verify_verify.set_defaults(handler=_handle_publish_verify, format_hint="builder_summary", force_json_output=True)
|
|
236
283
|
|
|
237
284
|
view = builder_subparsers.add_parser("view", help="视图详情")
|
|
238
285
|
view_subparsers = view.add_subparsers(dest="builder_view_command", required=True)
|
|
@@ -280,6 +327,10 @@ def _handle_contract(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
280
327
|
return context.builder.builder_tool_contract(tool_name=args.tool_name)
|
|
281
328
|
|
|
282
329
|
|
|
330
|
+
def _handle_icon_catalog(args: argparse.Namespace, context: CliContext) -> dict:
|
|
331
|
+
return context.builder.workspace_icon_catalog_get(profile=args.profile)
|
|
332
|
+
|
|
333
|
+
|
|
283
334
|
def _handle_member_search(args: argparse.Namespace, context: CliContext) -> dict:
|
|
284
335
|
return context.builder.member_search(
|
|
285
336
|
profile=args.profile,
|
|
@@ -323,6 +374,10 @@ def _handle_package_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
323
374
|
return context.builder.package_get(profile=args.profile, package_id=args.package_id)
|
|
324
375
|
|
|
325
376
|
|
|
377
|
+
def _handle_package_list(args: argparse.Namespace, context: CliContext) -> dict:
|
|
378
|
+
return context.builder.package_list(profile=args.profile, trial_status=args.trial_status, query=args.query)
|
|
379
|
+
|
|
380
|
+
|
|
326
381
|
def _handle_package_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
327
382
|
config = load_object_arg(args.config_file, option_name="--config-file")
|
|
328
383
|
if not isinstance(config, dict):
|
|
@@ -369,8 +424,67 @@ def _handle_button_catalog(args: argparse.Namespace, context: CliContext) -> dic
|
|
|
369
424
|
return context.builder.button_style_catalog_get(profile=args.profile)
|
|
370
425
|
|
|
371
426
|
|
|
427
|
+
def _handle_button_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
428
|
+
apps = load_list_arg(getattr(args, "apps_file", None), option_name="--apps-file")
|
|
429
|
+
if apps:
|
|
430
|
+
single_app_args = [a for a in ["--app-key" if args.app_key else None, "--upsert-buttons-file" if getattr(args, "upsert_buttons_file", None) else None, "--patch-buttons-file" if getattr(args, "patch_buttons_file", None) else None, "--remove-buttons-file" if getattr(args, "remove_buttons_file", None) else None, "--view-configs-file" if getattr(args, "view_configs_file", None) else None] if a]
|
|
431
|
+
if single_app_args:
|
|
432
|
+
raise_config_error(
|
|
433
|
+
f"button apply --apps-file cannot be combined with {', '.join(single_app_args)}.",
|
|
434
|
+
fix_hint="Use --apps-file for batch mode (each item contains app_key + per-app params), or remove --apps-file for single-app mode.",
|
|
435
|
+
)
|
|
436
|
+
if apps:
|
|
437
|
+
return context.builder.app_custom_buttons_apply(
|
|
438
|
+
profile=args.profile,
|
|
439
|
+
app_key="",
|
|
440
|
+
upsert_buttons=[],
|
|
441
|
+
patch_buttons=[],
|
|
442
|
+
remove_buttons=[],
|
|
443
|
+
view_configs=[],
|
|
444
|
+
apps=apps,
|
|
445
|
+
)
|
|
446
|
+
if not args.app_key:
|
|
447
|
+
raise_config_error("button apply requires --app-key or --apps-file", fix_hint="Pass --app-key APP_KEY for single-app mode, or --apps-file for batch mode.")
|
|
448
|
+
return context.builder.app_custom_buttons_apply(
|
|
449
|
+
profile=args.profile,
|
|
450
|
+
app_key=args.app_key,
|
|
451
|
+
upsert_buttons=load_list_arg(args.upsert_buttons_file, option_name="--upsert-buttons-file"),
|
|
452
|
+
patch_buttons=load_list_arg(args.patch_buttons_file, option_name="--patch-buttons-file"),
|
|
453
|
+
remove_buttons=load_list_arg(args.remove_buttons_file, option_name="--remove-buttons-file"),
|
|
454
|
+
view_configs=load_list_arg(args.view_configs_file, option_name="--view-configs-file"),
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def _handle_associated_resource_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
459
|
+
return context.builder.app_associated_resources_apply(
|
|
460
|
+
profile=args.profile,
|
|
461
|
+
app_key=args.app_key,
|
|
462
|
+
upsert_resources=load_list_arg(args.upsert_resources_file, option_name="--upsert-resources-file"),
|
|
463
|
+
patch_resources=load_list_arg(args.patch_resources_file, option_name="--patch-resources-file"),
|
|
464
|
+
remove_associated_item_ids=load_list_arg(args.remove_associated_item_ids_file, option_name="--remove-associated-item-ids-file"),
|
|
465
|
+
reorder_associated_item_ids=load_list_arg(args.reorder_associated_item_ids_file, option_name="--reorder-associated-item-ids-file"),
|
|
466
|
+
view_configs=load_list_arg(args.view_configs_file, option_name="--view-configs-file"),
|
|
467
|
+
)
|
|
468
|
+
|
|
469
|
+
|
|
372
470
|
def _handle_button_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
373
|
-
|
|
471
|
+
app_keys = _parse_app_keys_arg(getattr(args, "app_keys", None))
|
|
472
|
+
if app_keys:
|
|
473
|
+
return context.builder.app_get_buttons(profile=args.profile, app_keys=app_keys)
|
|
474
|
+
app_key = str(getattr(args, "app_key", "") or "").strip()
|
|
475
|
+
if not app_key:
|
|
476
|
+
raise_config_error("button get requires --app-key or --app-keys", fix_hint="Pass --app-key APP_KEY or --app-keys KEY1,KEY2")
|
|
477
|
+
return context.builder.app_get_buttons(profile=args.profile, app_key=app_key)
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def _handle_associated_resource_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
481
|
+
app_keys = _parse_app_keys_arg(getattr(args, "app_keys", None))
|
|
482
|
+
if app_keys:
|
|
483
|
+
return context.builder.app_get_associated_resources(profile=args.profile, app_keys=app_keys)
|
|
484
|
+
app_key = str(getattr(args, "app_key", "") or "").strip()
|
|
485
|
+
if not app_key:
|
|
486
|
+
raise_config_error("associated-resource get requires --app-key or --app-keys", fix_hint="Pass --app-key APP_KEY or --app-keys KEY1,KEY2")
|
|
487
|
+
return context.builder.app_get_associated_resources(profile=args.profile, app_key=app_key)
|
|
374
488
|
|
|
375
489
|
|
|
376
490
|
def _handle_button_create(args: argparse.Namespace, context: CliContext) -> dict:
|
|
@@ -395,6 +509,30 @@ def _handle_button_delete(args: argparse.Namespace, context: CliContext) -> dict
|
|
|
395
509
|
|
|
396
510
|
|
|
397
511
|
def _handle_app_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
512
|
+
section = args.builder_app_get_section
|
|
513
|
+
app_keys = _parse_app_keys_arg(getattr(args, "app_keys", None))
|
|
514
|
+
app_key = str(getattr(args, "app_key", "") or "").strip()
|
|
515
|
+
if not app_keys and not app_key:
|
|
516
|
+
raise_config_error("app get requires --app-key or --app-keys", fix_hint="Pass --app-key APP_KEY or --app-keys KEY1,KEY2")
|
|
517
|
+
if section == "buttons":
|
|
518
|
+
if app_keys:
|
|
519
|
+
return context.builder.app_get_buttons(profile=args.profile, app_keys=app_keys)
|
|
520
|
+
return context.builder.app_get_buttons(profile=args.profile, app_key=app_key)
|
|
521
|
+
if section == "associated-resources":
|
|
522
|
+
if app_keys:
|
|
523
|
+
return context.builder.app_get_associated_resources(profile=args.profile, app_keys=app_keys)
|
|
524
|
+
return context.builder.app_get_associated_resources(profile=args.profile, app_key=app_key)
|
|
525
|
+
if app_keys:
|
|
526
|
+
batch_handlers = {
|
|
527
|
+
"fields": context.builder.app_get_fields,
|
|
528
|
+
"layout": context.builder.app_get_layout,
|
|
529
|
+
"views": context.builder.app_get_views,
|
|
530
|
+
"flow": context.builder.app_get_flow,
|
|
531
|
+
"charts": context.builder.app_get_charts,
|
|
532
|
+
}
|
|
533
|
+
if section not in batch_handlers:
|
|
534
|
+
raise_config_error(f"app get --app-keys does not support section '{section}'", fix_hint="Batch reads support: fields, layout, views, flow, charts, buttons, associated-resources")
|
|
535
|
+
return batch_handlers[section](profile=args.profile, app_keys=app_keys)
|
|
398
536
|
handlers = {
|
|
399
537
|
"summary": context.builder.app_get,
|
|
400
538
|
"fields": context.builder.app_get_fields,
|
|
@@ -403,7 +541,7 @@ def _handle_app_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
403
541
|
"flow": context.builder.app_get_flow,
|
|
404
542
|
"charts": context.builder.app_get_charts,
|
|
405
543
|
}
|
|
406
|
-
return handlers[
|
|
544
|
+
return handlers[section](profile=args.profile, app_key=app_key)
|
|
407
545
|
|
|
408
546
|
|
|
409
547
|
def _handle_app_repair_code_blocks(args: argparse.Namespace, context: CliContext) -> dict:
|
|
@@ -432,6 +570,34 @@ def _handle_chart_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
432
570
|
|
|
433
571
|
|
|
434
572
|
def _handle_schema_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
573
|
+
apps = load_list_arg(args.apps_file, option_name="--apps-file")
|
|
574
|
+
if args.apps_file:
|
|
575
|
+
if not apps:
|
|
576
|
+
raise_config_error(
|
|
577
|
+
"schema apply multi-app mode requires a non-empty --apps-file.",
|
|
578
|
+
fix_hint="Pass a JSON array with at least one app item.",
|
|
579
|
+
)
|
|
580
|
+
if args.app_key or args.app_name or args.app_title or args.add_fields_file or args.update_fields_file or args.remove_fields_file:
|
|
581
|
+
raise_config_error(
|
|
582
|
+
"schema apply multi-app mode accepts --package-id/--create-if-missing plus --apps-file only.",
|
|
583
|
+
fix_hint="Use `--apps-file` for batch mode, or remove `--apps-file` and use the single-app arguments.",
|
|
584
|
+
)
|
|
585
|
+
if args.package_id is None:
|
|
586
|
+
raise_config_error(
|
|
587
|
+
"schema apply multi-app mode requires --package-id.",
|
|
588
|
+
fix_hint="Pass `--package-id` and app names inside --apps-file.",
|
|
589
|
+
)
|
|
590
|
+
return context.builder.app_schema_apply(
|
|
591
|
+
profile=args.profile,
|
|
592
|
+
package_id=args.package_id,
|
|
593
|
+
visibility=load_object_arg(args.visibility_file, option_name="--visibility-file"),
|
|
594
|
+
create_if_missing=bool(args.create_if_missing),
|
|
595
|
+
publish=bool(args.publish),
|
|
596
|
+
apps=apps,
|
|
597
|
+
add_fields=[],
|
|
598
|
+
update_fields=[],
|
|
599
|
+
remove_fields=[],
|
|
600
|
+
)
|
|
435
601
|
has_app_key = bool((args.app_key or "").strip())
|
|
436
602
|
has_app_name = bool((args.app_name or "").strip())
|
|
437
603
|
has_app_title = bool((args.app_title or "").strip())
|
|
@@ -466,6 +632,25 @@ def _handle_schema_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
466
632
|
|
|
467
633
|
|
|
468
634
|
def _handle_layout_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
635
|
+
apps = load_list_arg(getattr(args, "apps_file", None), option_name="--apps-file")
|
|
636
|
+
if apps:
|
|
637
|
+
single_app_args = [a for a in ["--app-key" if args.app_key else None, "--sections-file" if getattr(args, "sections_file", None) else None] if a]
|
|
638
|
+
if single_app_args:
|
|
639
|
+
raise_config_error(
|
|
640
|
+
f"layout apply --apps-file cannot be combined with {', '.join(single_app_args)}.",
|
|
641
|
+
fix_hint="Use --apps-file for batch mode (each item contains app_key + sections), or remove --apps-file for single-app mode.",
|
|
642
|
+
)
|
|
643
|
+
if apps:
|
|
644
|
+
return context.builder.app_layout_apply(
|
|
645
|
+
profile=args.profile,
|
|
646
|
+
app_key="",
|
|
647
|
+
mode=args.mode,
|
|
648
|
+
publish=bool(args.publish),
|
|
649
|
+
sections=[],
|
|
650
|
+
apps=apps,
|
|
651
|
+
)
|
|
652
|
+
if not args.app_key:
|
|
653
|
+
raise_config_error("layout apply requires --app-key or --apps-file", fix_hint="Pass --app-key + --sections-file for single-app mode, or --apps-file for batch mode.")
|
|
469
654
|
return context.builder.app_layout_apply(
|
|
470
655
|
profile=args.profile,
|
|
471
656
|
app_key=args.app_key,
|
|
@@ -476,40 +661,144 @@ def _handle_layout_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
476
661
|
|
|
477
662
|
|
|
478
663
|
def _handle_views_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
664
|
+
apps = load_list_arg(getattr(args, "apps_file", None), option_name="--apps-file")
|
|
665
|
+
if apps:
|
|
666
|
+
single_app_args = [a for a in ["--app-key" if args.app_key else None, "--upsert-views-file" if getattr(args, "upsert_views_file", None) else None, "--patch-views-file" if getattr(args, "patch_views_file", None) else None, "--remove-views-file" if getattr(args, "remove_views_file", None) else None] if a]
|
|
667
|
+
if single_app_args:
|
|
668
|
+
raise_config_error(
|
|
669
|
+
f"views apply --apps-file cannot be combined with {', '.join(single_app_args)}.",
|
|
670
|
+
fix_hint="Use --apps-file for batch mode (each item contains app_key + per-app params), or remove --apps-file for single-app mode.",
|
|
671
|
+
)
|
|
672
|
+
if apps:
|
|
673
|
+
return context.builder.app_views_apply(
|
|
674
|
+
profile=args.profile,
|
|
675
|
+
app_key="",
|
|
676
|
+
publish=bool(args.publish),
|
|
677
|
+
upsert_views=[],
|
|
678
|
+
patch_views=[],
|
|
679
|
+
remove_views=[],
|
|
680
|
+
apps=apps,
|
|
681
|
+
)
|
|
682
|
+
if not args.app_key:
|
|
683
|
+
raise_config_error("views apply requires --app-key or --apps-file", fix_hint="Pass --app-key for single-app mode, or --apps-file for batch mode.")
|
|
479
684
|
return context.builder.app_views_apply(
|
|
480
685
|
profile=args.profile,
|
|
481
686
|
app_key=args.app_key,
|
|
482
687
|
publish=bool(args.publish),
|
|
483
688
|
upsert_views=load_list_arg(args.upsert_views_file, option_name="--upsert-views-file"),
|
|
689
|
+
patch_views=load_list_arg(args.patch_views_file, option_name="--patch-views-file"),
|
|
484
690
|
remove_views=load_list_arg(args.remove_views_file, option_name="--remove-views-file"),
|
|
485
691
|
)
|
|
486
692
|
|
|
487
693
|
|
|
694
|
+
def _handle_flow_schema(args: argparse.Namespace, context: CliContext) -> dict:
|
|
695
|
+
return context.builder.app_flow_get_schema(
|
|
696
|
+
profile=args.profile,
|
|
697
|
+
schema_version=args.schema_version or None,
|
|
698
|
+
)
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
def _handle_flow_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
702
|
+
return context.builder.app_get_flow(
|
|
703
|
+
profile=args.profile,
|
|
704
|
+
app_key=args.app_key,
|
|
705
|
+
version_id=args.version_id or None,
|
|
706
|
+
)
|
|
707
|
+
|
|
708
|
+
|
|
488
709
|
def _handle_flow_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
710
|
+
patch_nodes = load_list_arg(getattr(args, "patch_nodes_file", None), option_name="--patch-nodes-file")
|
|
711
|
+
if patch_nodes and args.spec_file:
|
|
712
|
+
raise_config_error(
|
|
713
|
+
"flow apply --spec-file and --patch-nodes-file are mutually exclusive.",
|
|
714
|
+
fix_hint="Use --spec-file to replace the full flow spec, or --patch-nodes-file to patch specific nodes.",
|
|
715
|
+
)
|
|
716
|
+
if patch_nodes:
|
|
717
|
+
return context.builder.app_flow_apply(
|
|
718
|
+
profile=args.profile,
|
|
719
|
+
app_key=args.app_key,
|
|
720
|
+
publish=bool(args.publish),
|
|
721
|
+
spec=None,
|
|
722
|
+
patch_nodes=patch_nodes,
|
|
723
|
+
idempotency_key=args.idempotency_key or None,
|
|
724
|
+
schema_version=args.schema_version or None,
|
|
725
|
+
)
|
|
726
|
+
spec_payload = load_object_arg(args.spec_file, option_name="--spec-file") if args.spec_file else None
|
|
727
|
+
if not isinstance(spec_payload, dict):
|
|
728
|
+
raise_config_error("flow apply requires either --spec-file or --patch-nodes-file.", fix_hint="Pass --spec-file to replace the full flow spec, or --patch-nodes-file to patch specific nodes.")
|
|
729
|
+
if "spec" in spec_payload and isinstance(spec_payload.get("spec"), dict):
|
|
730
|
+
spec = spec_payload["spec"]
|
|
731
|
+
else:
|
|
732
|
+
spec = spec_payload
|
|
489
733
|
return context.builder.app_flow_apply(
|
|
490
734
|
profile=args.profile,
|
|
491
735
|
app_key=args.app_key,
|
|
492
|
-
mode=args.mode,
|
|
493
736
|
publish=bool(args.publish),
|
|
494
|
-
|
|
495
|
-
|
|
737
|
+
spec=spec,
|
|
738
|
+
idempotency_key=args.idempotency_key or None,
|
|
739
|
+
schema_version=args.schema_version or None,
|
|
496
740
|
)
|
|
497
741
|
|
|
498
742
|
|
|
499
743
|
def _handle_charts_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
744
|
+
apps = load_list_arg(getattr(args, "apps_file", None), option_name="--apps-file")
|
|
745
|
+
if apps:
|
|
746
|
+
single_app_args = [a for a in ["--app-key" if args.app_key else None, "--upsert-file" if getattr(args, "upsert_file", None) else None, "--patch-file" if getattr(args, "patch_file", None) else None, "--remove-chart-ids-file" if getattr(args, "remove_chart_ids_file", None) else None, "--reorder-chart-ids-file" if getattr(args, "reorder_chart_ids_file", None) else None] if a]
|
|
747
|
+
if single_app_args:
|
|
748
|
+
raise_config_error(
|
|
749
|
+
f"charts apply --apps-file cannot be combined with {', '.join(single_app_args)}.",
|
|
750
|
+
fix_hint="Use --apps-file for batch mode (each item contains app_key + per-app params), or remove --apps-file for single-app mode.",
|
|
751
|
+
)
|
|
752
|
+
if apps:
|
|
753
|
+
return context.builder.app_charts_apply(
|
|
754
|
+
profile=args.profile,
|
|
755
|
+
app_key="",
|
|
756
|
+
upsert_charts=[],
|
|
757
|
+
patch_charts=[],
|
|
758
|
+
remove_chart_ids=[],
|
|
759
|
+
reorder_chart_ids=[],
|
|
760
|
+
apps=apps,
|
|
761
|
+
)
|
|
762
|
+
if not args.app_key:
|
|
763
|
+
raise_config_error("charts apply requires --app-key or --apps-file", fix_hint="Pass --app-key for single-app mode, or --apps-file for batch mode.")
|
|
500
764
|
return context.builder.app_charts_apply(
|
|
501
765
|
profile=args.profile,
|
|
502
766
|
app_key=args.app_key,
|
|
503
767
|
upsert_charts=load_list_arg(args.upsert_file, option_name="--upsert-file"),
|
|
768
|
+
patch_charts=load_list_arg(args.patch_file, option_name="--patch-file"),
|
|
504
769
|
remove_chart_ids=load_list_arg(args.remove_chart_ids_file, option_name="--remove-chart-ids-file"),
|
|
505
770
|
reorder_chart_ids=load_list_arg(args.reorder_chart_ids_file, option_name="--reorder-chart-ids-file"),
|
|
506
771
|
)
|
|
507
772
|
|
|
508
773
|
|
|
509
774
|
def _handle_portal_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
775
|
+
patch_sections = load_list_arg(getattr(args, "patch_sections_file", None), option_name="--patch-sections-file")
|
|
776
|
+
if patch_sections:
|
|
777
|
+
if not (args.dash_key or "").strip():
|
|
778
|
+
raise_config_error("portal apply --patch-sections-file requires --dash-key", fix_hint="Pass --dash-key DASH_KEY to identify the portal to patch")
|
|
779
|
+
has_sections_file = bool(getattr(args, "sections_file", None))
|
|
780
|
+
has_payload_file = bool(getattr(args, "payload_file", None))
|
|
781
|
+
if has_sections_file or has_payload_file:
|
|
782
|
+
raise_config_error(
|
|
783
|
+
"portal apply --patch-sections-file cannot be combined with --sections-file or --payload-file.",
|
|
784
|
+
fix_hint="Use --patch-sections-file alone to patch specific sections, or --sections-file to replace all sections.",
|
|
785
|
+
)
|
|
786
|
+
return context.builder.portal_apply(
|
|
787
|
+
profile=args.profile,
|
|
788
|
+
dash_key=args.dash_key,
|
|
789
|
+
dash_name="",
|
|
790
|
+
package_id=None,
|
|
791
|
+
publish=bool(args.publish),
|
|
792
|
+
sections=[],
|
|
793
|
+
patch_sections=patch_sections,
|
|
794
|
+
)
|
|
795
|
+
payload = load_object_arg(args.payload_file, option_name="--payload-file") if getattr(args, "payload_file", None) else None
|
|
796
|
+
payload_obj = payload if isinstance(payload, dict) else {}
|
|
797
|
+
effective_dash_name = (args.dash_name or str(payload_obj.get("dash_name") or payload_obj.get("dashName") or payload_obj.get("name") or "")).strip()
|
|
798
|
+
effective_package_id = args.package_id if args.package_id is not None else payload_obj.get("package_id") or payload_obj.get("packageId") or payload_obj.get("package_tag_id")
|
|
510
799
|
has_dash_key = bool((args.dash_key or "").strip())
|
|
511
|
-
has_dash_name = bool(
|
|
512
|
-
has_package_id =
|
|
800
|
+
has_dash_name = bool(effective_dash_name)
|
|
801
|
+
has_package_id = effective_package_id is not None
|
|
513
802
|
if has_dash_key and has_package_id:
|
|
514
803
|
raise_config_error(
|
|
515
804
|
"portal apply accepts exactly one selector mode.",
|
|
@@ -528,6 +817,7 @@ def _handle_portal_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
528
817
|
package_id=args.package_id,
|
|
529
818
|
publish=bool(args.publish),
|
|
530
819
|
sections=sections,
|
|
820
|
+
layout_preset=args.layout_preset,
|
|
531
821
|
visibility=load_object_arg(args.visibility_file, option_name="--visibility-file"),
|
|
532
822
|
auth=load_object_arg(args.auth_file, option_name="--auth-file"),
|
|
533
823
|
icon=args.icon,
|
|
@@ -535,10 +825,18 @@ def _handle_portal_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
|
535
825
|
hide_copyright=args.hide_copyright,
|
|
536
826
|
dash_global_config=load_object_arg(args.dash_global_config_file, option_name="--dash-global-config-file"),
|
|
537
827
|
config=load_object_arg(args.config_file, option_name="--config-file"),
|
|
828
|
+
payload=payload,
|
|
538
829
|
)
|
|
539
830
|
|
|
540
831
|
|
|
541
832
|
def _handle_publish_verify(args: argparse.Namespace, context: CliContext) -> dict:
|
|
833
|
+
app_keys = _parse_app_keys_arg(getattr(args, "app_keys", None))
|
|
834
|
+
if app_keys:
|
|
835
|
+
return context.builder.app_publish_verify(
|
|
836
|
+
profile=args.profile,
|
|
837
|
+
app_keys=app_keys,
|
|
838
|
+
expected_package_id=args.expected_package_id,
|
|
839
|
+
)
|
|
542
840
|
return context.builder.app_publish_verify(
|
|
543
841
|
profile=args.profile,
|
|
544
842
|
app_key=args.app_key,
|