@josephyan/qingflow-app-builder-mcp 0.2.0-beta.7 → 0.2.0-beta.71
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 +5 -3
- package/docs/local-agent-install.md +21 -5
- package/npm/bin/qingflow-app-builder-mcp.mjs +1 -1
- package/npm/lib/runtime.mjs +168 -12
- package/package.json +1 -1
- package/pyproject.toml +4 -1
- package/skills/qingflow-app-builder/SKILL.md +155 -22
- package/skills/qingflow-app-builder/references/create-app.md +51 -21
- package/skills/qingflow-app-builder/references/environments.md +1 -1
- package/skills/qingflow-app-builder/references/flow-actors-and-permissions.md +123 -0
- package/skills/qingflow-app-builder/references/gotchas.md +28 -1
- package/skills/qingflow-app-builder/references/solution-playbooks.md +14 -12
- package/skills/qingflow-app-builder/references/tool-selection.md +47 -19
- package/skills/qingflow-app-builder/references/update-flow.md +112 -25
- package/skills/qingflow-app-builder/references/update-layout.md +11 -24
- package/skills/qingflow-app-builder/references/update-schema.md +1 -23
- package/skills/qingflow-app-builder/references/update-views.md +87 -21
- package/skills/qingflow-app-builder-code-integrations/SKILL.md +137 -0
- package/skills/qingflow-app-builder-code-integrations/agents/openai.yaml +4 -0
- package/skills/qingflow-app-builder-code-integrations/references/code-block.md +66 -0
- package/skills/qingflow-app-builder-code-integrations/references/q-linker.md +77 -0
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/backend_client.py +210 -0
- package/src/qingflow_mcp/builder_facade/models.py +1252 -3
- package/src/qingflow_mcp/builder_facade/service.py +11367 -2389
- package/src/qingflow_mcp/cli/__init__.py +1 -0
- package/src/qingflow_mcp/cli/commands/__init__.py +15 -0
- package/src/qingflow_mcp/cli/commands/app.py +40 -0
- package/src/qingflow_mcp/cli/commands/auth.py +78 -0
- package/src/qingflow_mcp/cli/commands/builder.py +515 -0
- package/src/qingflow_mcp/cli/commands/common.py +62 -0
- package/src/qingflow_mcp/cli/commands/imports.py +96 -0
- package/src/qingflow_mcp/cli/commands/record.py +304 -0
- package/src/qingflow_mcp/cli/commands/task.py +89 -0
- package/src/qingflow_mcp/cli/commands/workspace.py +33 -0
- package/src/qingflow_mcp/cli/context.py +48 -0
- package/src/qingflow_mcp/cli/formatters.py +355 -0
- package/src/qingflow_mcp/cli/json_io.py +50 -0
- package/src/qingflow_mcp/cli/main.py +149 -0
- package/src/qingflow_mcp/config.py +39 -0
- package/src/qingflow_mcp/import_store.py +121 -0
- package/src/qingflow_mcp/list_type_labels.py +24 -0
- package/src/qingflow_mcp/response_trim.py +668 -0
- package/src/qingflow_mcp/server.py +160 -18
- package/src/qingflow_mcp/server_app_builder.py +275 -68
- package/src/qingflow_mcp/server_app_user.py +219 -191
- package/src/qingflow_mcp/session_store.py +41 -1
- package/src/qingflow_mcp/solution/compiler/form_compiler.py +43 -4
- package/src/qingflow_mcp/solution/compiler/icon_utils.py +119 -45
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +41 -2
- package/src/qingflow_mcp/solution/executor.py +107 -11
- package/src/qingflow_mcp/solution/spec_models.py +2 -0
- package/src/qingflow_mcp/tools/ai_builder_tools.py +2032 -127
- package/src/qingflow_mcp/tools/app_tools.py +419 -12
- package/src/qingflow_mcp/tools/approval_tools.py +571 -72
- package/src/qingflow_mcp/tools/auth_tools.py +398 -2
- package/src/qingflow_mcp/tools/code_block_tools.py +756 -0
- package/src/qingflow_mcp/tools/custom_button_tools.py +179 -0
- package/src/qingflow_mcp/tools/directory_tools.py +203 -31
- package/src/qingflow_mcp/tools/feedback_tools.py +230 -0
- package/src/qingflow_mcp/tools/file_tools.py +1 -0
- package/src/qingflow_mcp/tools/import_tools.py +2150 -0
- package/src/qingflow_mcp/tools/package_tools.py +18 -4
- package/src/qingflow_mcp/tools/portal_tools.py +31 -0
- package/src/qingflow_mcp/tools/qingbi_report_tools.py +109 -7
- package/src/qingflow_mcp/tools/record_tools.py +9894 -1104
- package/src/qingflow_mcp/tools/solution_tools.py +115 -3
- package/src/qingflow_mcp/tools/task_context_tools.py +2040 -0
- package/src/qingflow_mcp/tools/task_tools.py +376 -225
- package/src/qingflow_mcp/tools/workspace_tools.py +163 -19
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__all__: list[str] = []
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
from . import app, auth, builder, imports, record, task, workspace
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def register_all_commands(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
|
|
9
|
+
auth.register(subparsers)
|
|
10
|
+
workspace.register(subparsers)
|
|
11
|
+
app.register(subparsers)
|
|
12
|
+
record.register(subparsers)
|
|
13
|
+
imports.register(subparsers)
|
|
14
|
+
task.register(subparsers)
|
|
15
|
+
builder.register(subparsers)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
from ..context import CliContext
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
|
|
9
|
+
parser = subparsers.add_parser("app", help="应用发现")
|
|
10
|
+
app_subparsers = parser.add_subparsers(dest="app_command", required=True)
|
|
11
|
+
|
|
12
|
+
list_parser = app_subparsers.add_parser("list", help="列出可见应用")
|
|
13
|
+
list_parser.set_defaults(handler=_handle_list, format_hint="app_list")
|
|
14
|
+
|
|
15
|
+
search = app_subparsers.add_parser("search", help="搜索应用")
|
|
16
|
+
search.add_argument("--keyword", default="")
|
|
17
|
+
search.add_argument("--page", type=int, default=1)
|
|
18
|
+
search.add_argument("--page-size", type=int, default=50)
|
|
19
|
+
search.set_defaults(handler=_handle_search, format_hint="app_search")
|
|
20
|
+
|
|
21
|
+
get = app_subparsers.add_parser("get", help="读取应用可访问视图与导入能力")
|
|
22
|
+
get.add_argument("--app-key", required=True)
|
|
23
|
+
get.set_defaults(handler=_handle_get, format_hint="app_get")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _handle_list(args: argparse.Namespace, context: CliContext) -> dict:
|
|
27
|
+
return context.app.app_list(profile=args.profile)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _handle_search(args: argparse.Namespace, context: CliContext) -> dict:
|
|
31
|
+
return context.app.app_search(
|
|
32
|
+
profile=args.profile,
|
|
33
|
+
keyword=args.keyword,
|
|
34
|
+
page_num=args.page,
|
|
35
|
+
page_size=args.page_size,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _handle_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
40
|
+
return context.app.app_get(profile=args.profile, app_key=args.app_key)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import getpass
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from ...errors import QingflowApiError
|
|
8
|
+
from ..context import CliContext
|
|
9
|
+
from .common import read_secret_arg
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
|
|
13
|
+
parser = subparsers.add_parser("auth", help="认证与会话")
|
|
14
|
+
auth_subparsers = parser.add_subparsers(dest="auth_command", required=True)
|
|
15
|
+
|
|
16
|
+
login = auth_subparsers.add_parser("login", help="邮箱密码登录")
|
|
17
|
+
login.add_argument("--base-url")
|
|
18
|
+
login.add_argument("--qf-version")
|
|
19
|
+
login.add_argument("--email", required=True)
|
|
20
|
+
login.add_argument("--password")
|
|
21
|
+
login.add_argument("--password-stdin", action="store_true")
|
|
22
|
+
login.add_argument("--persist", action=argparse.BooleanOptionalAction, default=True)
|
|
23
|
+
login.set_defaults(handler=_handle_login, format_hint="auth_whoami")
|
|
24
|
+
|
|
25
|
+
use_token = auth_subparsers.add_parser("use-token", help="直接注入 token")
|
|
26
|
+
use_token.add_argument("--base-url")
|
|
27
|
+
use_token.add_argument("--qf-version")
|
|
28
|
+
use_token.add_argument("--token")
|
|
29
|
+
use_token.add_argument("--token-stdin", action="store_true")
|
|
30
|
+
use_token.add_argument("--ws-id", type=int)
|
|
31
|
+
use_token.add_argument("--persist", action=argparse.BooleanOptionalAction, default=False)
|
|
32
|
+
use_token.set_defaults(handler=_handle_use_token, format_hint="auth_whoami")
|
|
33
|
+
|
|
34
|
+
whoami = auth_subparsers.add_parser("whoami", help="查看当前登录态")
|
|
35
|
+
whoami.set_defaults(handler=_handle_whoami, format_hint="auth_whoami")
|
|
36
|
+
|
|
37
|
+
logout = auth_subparsers.add_parser("logout", help="退出登录")
|
|
38
|
+
logout.add_argument("--forget-persisted", action="store_true")
|
|
39
|
+
logout.set_defaults(handler=_handle_logout, format_hint="")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _handle_login(args: argparse.Namespace, context: CliContext) -> dict:
|
|
43
|
+
password = args.password
|
|
44
|
+
if args.password_stdin:
|
|
45
|
+
password = read_secret_arg(args.password, stdin_enabled=True, label="password")
|
|
46
|
+
elif not password:
|
|
47
|
+
if sys.stdin.isatty():
|
|
48
|
+
password = getpass.getpass("Password: ")
|
|
49
|
+
else:
|
|
50
|
+
raise QingflowApiError.config_error("password is required; use --password or --password-stdin")
|
|
51
|
+
return context.auth.auth_login(
|
|
52
|
+
profile=args.profile,
|
|
53
|
+
base_url=args.base_url,
|
|
54
|
+
qf_version=args.qf_version,
|
|
55
|
+
email=args.email,
|
|
56
|
+
password=password,
|
|
57
|
+
persist=bool(args.persist),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _handle_use_token(args: argparse.Namespace, context: CliContext) -> dict:
|
|
62
|
+
token = read_secret_arg(args.token, stdin_enabled=bool(args.token_stdin), label="token")
|
|
63
|
+
return context.auth.auth_use_token(
|
|
64
|
+
profile=args.profile,
|
|
65
|
+
base_url=args.base_url,
|
|
66
|
+
qf_version=args.qf_version,
|
|
67
|
+
token=token,
|
|
68
|
+
ws_id=args.ws_id,
|
|
69
|
+
persist=bool(args.persist),
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _handle_whoami(args: argparse.Namespace, context: CliContext) -> dict:
|
|
74
|
+
return context.auth.auth_whoami(profile=args.profile)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _handle_logout(args: argparse.Namespace, context: CliContext) -> dict:
|
|
78
|
+
return context.auth.auth_logout(profile=args.profile, forget_persisted=bool(args.forget_persisted))
|
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
from ..context import CliContext
|
|
6
|
+
from .common import load_list_arg, load_object_arg, raise_config_error, require_list_arg
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
|
|
10
|
+
parser = subparsers.add_parser("builder", aliases=["build"], help="稳定 builder 命令")
|
|
11
|
+
builder_subparsers = parser.add_subparsers(dest="builder_command", required=True)
|
|
12
|
+
|
|
13
|
+
contract = builder_subparsers.add_parser("contract", help="读取 builder tool 合约")
|
|
14
|
+
contract.add_argument("--tool-name", required=True)
|
|
15
|
+
contract.set_defaults(handler=_handle_contract, format_hint="builder_summary")
|
|
16
|
+
|
|
17
|
+
member = builder_subparsers.add_parser("member", help="成员目录")
|
|
18
|
+
member_subparsers = member.add_subparsers(dest="builder_member_command", required=True)
|
|
19
|
+
member_search = member_subparsers.add_parser("search", help="搜索成员")
|
|
20
|
+
member_search.add_argument("--query", default="")
|
|
21
|
+
member_search.add_argument("--page-num", type=int, default=1)
|
|
22
|
+
member_search.add_argument("--page-size", type=int, default=20)
|
|
23
|
+
member_search.add_argument("--contain-disable", action=argparse.BooleanOptionalAction, default=False)
|
|
24
|
+
member_search.set_defaults(handler=_handle_member_search, format_hint="builder_summary")
|
|
25
|
+
|
|
26
|
+
role = builder_subparsers.add_parser("role", help="角色目录")
|
|
27
|
+
role_subparsers = role.add_subparsers(dest="builder_role_command", required=True)
|
|
28
|
+
role_search = role_subparsers.add_parser("search", help="搜索角色")
|
|
29
|
+
role_search.add_argument("--keyword", default="")
|
|
30
|
+
role_search.add_argument("--page-num", type=int, default=1)
|
|
31
|
+
role_search.add_argument("--page-size", type=int, default=20)
|
|
32
|
+
role_search.set_defaults(handler=_handle_role_search, format_hint="builder_summary")
|
|
33
|
+
|
|
34
|
+
role_create = role_subparsers.add_parser("create", help="创建角色")
|
|
35
|
+
role_create.add_argument("--role-name", required=True)
|
|
36
|
+
role_create.add_argument("--member-uids-file")
|
|
37
|
+
role_create.add_argument("--member-emails-file")
|
|
38
|
+
role_create.add_argument("--member-names-file")
|
|
39
|
+
role_create.add_argument("--role-icon", default="ex-user-outlined")
|
|
40
|
+
role_create.set_defaults(handler=_handle_role_create, format_hint="builder_summary")
|
|
41
|
+
|
|
42
|
+
package = builder_subparsers.add_parser("package", help="应用包")
|
|
43
|
+
package_subparsers = package.add_subparsers(dest="builder_package_command", required=True)
|
|
44
|
+
package_list = package_subparsers.add_parser("list", help="列出应用包")
|
|
45
|
+
package_list.add_argument("--trial-status", default="all")
|
|
46
|
+
package_list.set_defaults(handler=_handle_package_list, format_hint="builder_summary")
|
|
47
|
+
|
|
48
|
+
package_resolve = package_subparsers.add_parser("resolve", help="解析应用包")
|
|
49
|
+
package_resolve.add_argument("--package-name", required=True)
|
|
50
|
+
package_resolve.set_defaults(handler=_handle_package_resolve, format_hint="builder_summary")
|
|
51
|
+
|
|
52
|
+
package_create = package_subparsers.add_parser("create", help="创建应用包")
|
|
53
|
+
package_create.add_argument("--package-name", required=True)
|
|
54
|
+
package_create.add_argument("--icon")
|
|
55
|
+
package_create.add_argument("--color")
|
|
56
|
+
package_create.set_defaults(handler=_handle_package_create, format_hint="builder_summary")
|
|
57
|
+
|
|
58
|
+
package_attach_app = package_subparsers.add_parser("attach-app", help="将应用挂载到应用包")
|
|
59
|
+
package_attach_app.add_argument("--tag-id", type=int, required=True)
|
|
60
|
+
package_attach_app.add_argument("--app-key", required=True)
|
|
61
|
+
package_attach_app.add_argument("--app-title", dest="legacy_app_title", help=argparse.SUPPRESS)
|
|
62
|
+
package_attach_app.set_defaults(handler=_handle_package_attach_app, format_hint="builder_summary")
|
|
63
|
+
|
|
64
|
+
app = builder_subparsers.add_parser("app", help="应用")
|
|
65
|
+
app_subparsers = app.add_subparsers(dest="builder_app_command", required=True)
|
|
66
|
+
|
|
67
|
+
app_resolve = app_subparsers.add_parser("resolve", help="解析应用")
|
|
68
|
+
app_resolve.add_argument("--app-key", default="")
|
|
69
|
+
app_resolve.add_argument("--app-name", default="")
|
|
70
|
+
app_resolve.add_argument("--package-tag-id", type=int)
|
|
71
|
+
app_resolve.set_defaults(handler=_handle_app_resolve, format_hint="builder_summary")
|
|
72
|
+
|
|
73
|
+
app_release_lock = app_subparsers.add_parser("release-edit-lock-if-mine", help="释放当前账号持有的编辑锁")
|
|
74
|
+
app_release_lock.add_argument("--app-key", required=True)
|
|
75
|
+
app_release_lock.add_argument("--lock-owner-email", required=True)
|
|
76
|
+
app_release_lock.add_argument("--lock-owner-name", required=True)
|
|
77
|
+
app_release_lock.set_defaults(handler=_handle_app_release_edit_lock_if_mine, format_hint="builder_summary")
|
|
78
|
+
|
|
79
|
+
button = builder_subparsers.add_parser("button", help="自定义按钮")
|
|
80
|
+
button_subparsers = button.add_subparsers(dest="builder_button_command", required=True)
|
|
81
|
+
|
|
82
|
+
button_list = button_subparsers.add_parser("list", help="列出自定义按钮")
|
|
83
|
+
button_list.add_argument("--app-key", required=True)
|
|
84
|
+
button_list.set_defaults(handler=_handle_button_list, format_hint="builder_summary")
|
|
85
|
+
|
|
86
|
+
button_get = button_subparsers.add_parser("get", help="读取自定义按钮")
|
|
87
|
+
button_get.add_argument("--app-key", required=True)
|
|
88
|
+
button_get.add_argument("--button-id", type=int, required=True)
|
|
89
|
+
button_get.set_defaults(handler=_handle_button_get, format_hint="builder_summary")
|
|
90
|
+
|
|
91
|
+
button_create = button_subparsers.add_parser("create", help="创建自定义按钮")
|
|
92
|
+
button_create.add_argument("--app-key", required=True)
|
|
93
|
+
button_create.add_argument("--payload-file", required=True)
|
|
94
|
+
button_create.set_defaults(handler=_handle_button_create, format_hint="builder_summary")
|
|
95
|
+
|
|
96
|
+
button_update = button_subparsers.add_parser("update", help="更新自定义按钮")
|
|
97
|
+
button_update.add_argument("--app-key", required=True)
|
|
98
|
+
button_update.add_argument("--button-id", type=int, required=True)
|
|
99
|
+
button_update.add_argument("--payload-file", required=True)
|
|
100
|
+
button_update.set_defaults(handler=_handle_button_update, format_hint="builder_summary")
|
|
101
|
+
|
|
102
|
+
button_delete = button_subparsers.add_parser("delete", help="删除自定义按钮")
|
|
103
|
+
button_delete.add_argument("--app-key", required=True)
|
|
104
|
+
button_delete.add_argument("--button-id", type=int, required=True)
|
|
105
|
+
button_delete.set_defaults(handler=_handle_button_delete, format_hint="builder_summary")
|
|
106
|
+
|
|
107
|
+
for name, help_text, handler in [
|
|
108
|
+
("read-summary", "读取应用摘要", _handle_app_read_summary),
|
|
109
|
+
("read-fields", "读取字段摘要", _handle_app_read_fields),
|
|
110
|
+
("read-layout", "读取布局摘要", _handle_app_read_layout),
|
|
111
|
+
("read-views", "读取视图摘要", _handle_app_read_views),
|
|
112
|
+
("read-flow", "读取流程摘要", _handle_app_read_flow),
|
|
113
|
+
("read-charts", "读取报表摘要", _handle_app_read_charts),
|
|
114
|
+
]:
|
|
115
|
+
sub = app_subparsers.add_parser(name, help=help_text)
|
|
116
|
+
sub.add_argument("--app-key", required=True)
|
|
117
|
+
sub.set_defaults(handler=handler, format_hint="builder_summary")
|
|
118
|
+
|
|
119
|
+
portal = builder_subparsers.add_parser("portal", help="门户")
|
|
120
|
+
portal_subparsers = portal.add_subparsers(dest="builder_portal_command", required=True)
|
|
121
|
+
portal_list = portal_subparsers.add_parser("list", help="列出可访问门户")
|
|
122
|
+
portal_list.set_defaults(handler=_handle_portal_list, format_hint="builder_summary")
|
|
123
|
+
|
|
124
|
+
portal_get = portal_subparsers.add_parser("get", help="读取门户详情")
|
|
125
|
+
portal_get.add_argument("--dash-key", required=True)
|
|
126
|
+
portal_get.add_argument("--being-draft", action=argparse.BooleanOptionalAction, default=True)
|
|
127
|
+
portal_get.set_defaults(handler=_handle_portal_get, format_hint="builder_summary")
|
|
128
|
+
|
|
129
|
+
portal_read = portal_subparsers.add_parser("read-summary", help="读取门户摘要")
|
|
130
|
+
portal_read.add_argument("--dash-key", required=True)
|
|
131
|
+
portal_read.add_argument("--being-draft", action=argparse.BooleanOptionalAction, default=True)
|
|
132
|
+
portal_read.set_defaults(handler=_handle_portal_read_summary, format_hint="builder_summary")
|
|
133
|
+
|
|
134
|
+
portal_apply = portal_subparsers.add_parser("apply", help="更新门户")
|
|
135
|
+
portal_apply.add_argument("--dash-key", default="")
|
|
136
|
+
portal_apply.add_argument("--dash-name", default="")
|
|
137
|
+
portal_apply.add_argument("--package-tag-id", type=int)
|
|
138
|
+
portal_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
|
|
139
|
+
portal_apply.add_argument("--sections-file", required=True)
|
|
140
|
+
portal_apply.add_argument("--auth-file")
|
|
141
|
+
portal_apply.add_argument("--icon")
|
|
142
|
+
portal_apply.add_argument("--color")
|
|
143
|
+
portal_apply.add_argument("--hide-copyright", action=argparse.BooleanOptionalAction, default=None)
|
|
144
|
+
portal_apply.add_argument("--dash-global-config-file")
|
|
145
|
+
portal_apply.add_argument("--config-file")
|
|
146
|
+
portal_apply.set_defaults(handler=_handle_portal_apply, format_hint="builder_summary")
|
|
147
|
+
|
|
148
|
+
schema_apply = builder_subparsers.add_parser("schema", help="字段搭建")
|
|
149
|
+
schema_apply_subparsers = schema_apply.add_subparsers(dest="builder_schema_command", required=True)
|
|
150
|
+
schema_apply_apply = schema_apply_subparsers.add_parser("apply", help="执行字段变更")
|
|
151
|
+
schema_apply_apply.add_argument("--app-key", default="")
|
|
152
|
+
schema_apply_apply.add_argument("--package-tag-id", type=int)
|
|
153
|
+
schema_apply_apply.add_argument("--app-name", default="")
|
|
154
|
+
schema_apply_apply.add_argument("--app-title", default="")
|
|
155
|
+
schema_apply_apply.add_argument("--icon")
|
|
156
|
+
schema_apply_apply.add_argument("--color")
|
|
157
|
+
schema_apply_apply.add_argument("--create-if-missing", action="store_true")
|
|
158
|
+
schema_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
|
|
159
|
+
schema_apply_apply.add_argument("--add-fields-file")
|
|
160
|
+
schema_apply_apply.add_argument("--update-fields-file")
|
|
161
|
+
schema_apply_apply.add_argument("--remove-fields-file")
|
|
162
|
+
schema_apply_apply.set_defaults(handler=_handle_schema_apply, format_hint="builder_summary")
|
|
163
|
+
|
|
164
|
+
layout_apply = builder_subparsers.add_parser("layout", help="布局")
|
|
165
|
+
layout_apply_subparsers = layout_apply.add_subparsers(dest="builder_layout_command", required=True)
|
|
166
|
+
layout_apply_apply = layout_apply_subparsers.add_parser("apply", help="执行布局变更")
|
|
167
|
+
layout_apply_apply.add_argument("--app-key", required=True)
|
|
168
|
+
layout_apply_apply.add_argument("--mode", choices=["merge", "replace"], default="merge")
|
|
169
|
+
layout_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
|
|
170
|
+
layout_apply_apply.add_argument("--sections-file", required=True)
|
|
171
|
+
layout_apply_apply.set_defaults(handler=_handle_layout_apply, format_hint="builder_summary")
|
|
172
|
+
|
|
173
|
+
views_apply = builder_subparsers.add_parser("views", help="视图")
|
|
174
|
+
views_apply_subparsers = views_apply.add_subparsers(dest="builder_views_command", required=True)
|
|
175
|
+
views_apply_apply = views_apply_subparsers.add_parser("apply", help="执行视图变更")
|
|
176
|
+
views_apply_apply.add_argument("--app-key", required=True)
|
|
177
|
+
views_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
|
|
178
|
+
views_apply_apply.add_argument("--upsert-views-file")
|
|
179
|
+
views_apply_apply.add_argument("--remove-views-file")
|
|
180
|
+
views_apply_apply.set_defaults(handler=_handle_views_apply, format_hint="builder_summary")
|
|
181
|
+
|
|
182
|
+
flow_apply = builder_subparsers.add_parser("flow", help="流程")
|
|
183
|
+
flow_apply_subparsers = flow_apply.add_subparsers(dest="builder_flow_command", required=True)
|
|
184
|
+
flow_apply_apply = flow_apply_subparsers.add_parser("apply", help="执行流程变更")
|
|
185
|
+
flow_apply_apply.add_argument("--app-key", required=True)
|
|
186
|
+
flow_apply_apply.add_argument("--mode", choices=["replace"], default="replace")
|
|
187
|
+
flow_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
|
|
188
|
+
flow_apply_apply.add_argument("--nodes-file", required=True)
|
|
189
|
+
flow_apply_apply.add_argument("--transitions-file", required=True)
|
|
190
|
+
flow_apply_apply.set_defaults(handler=_handle_flow_apply, format_hint="builder_summary")
|
|
191
|
+
|
|
192
|
+
charts_apply = builder_subparsers.add_parser("charts", help="报表")
|
|
193
|
+
charts_apply_subparsers = charts_apply.add_subparsers(dest="builder_charts_command", required=True)
|
|
194
|
+
charts_apply_apply = charts_apply_subparsers.add_parser("apply", help="执行报表变更")
|
|
195
|
+
charts_apply_apply.add_argument("--app-key", required=True)
|
|
196
|
+
charts_apply_apply.add_argument("--upsert-file")
|
|
197
|
+
charts_apply_apply.add_argument("--remove-chart-ids-file")
|
|
198
|
+
charts_apply_apply.add_argument("--reorder-chart-ids-file")
|
|
199
|
+
charts_apply_apply.set_defaults(handler=_handle_charts_apply, format_hint="builder_summary")
|
|
200
|
+
|
|
201
|
+
publish_verify = builder_subparsers.add_parser("publish", help="发布校验")
|
|
202
|
+
publish_verify_subparsers = publish_verify.add_subparsers(dest="builder_publish_command", required=True)
|
|
203
|
+
publish_verify_verify = publish_verify_subparsers.add_parser("verify", help="校验应用发布")
|
|
204
|
+
publish_verify_verify.add_argument("--app-key", required=True)
|
|
205
|
+
publish_verify_verify.add_argument("--expected-package-tag-id", type=int)
|
|
206
|
+
publish_verify_verify.set_defaults(handler=_handle_publish_verify, format_hint="builder_summary")
|
|
207
|
+
|
|
208
|
+
view = builder_subparsers.add_parser("view", help="视图详情")
|
|
209
|
+
view_subparsers = view.add_subparsers(dest="builder_view_command", required=True)
|
|
210
|
+
view_get = view_subparsers.add_parser("get", help="读取视图详情")
|
|
211
|
+
view_get.add_argument("--viewgraph-key", required=True)
|
|
212
|
+
view_get.set_defaults(handler=_handle_view_get, format_hint="builder_summary")
|
|
213
|
+
|
|
214
|
+
chart = builder_subparsers.add_parser("chart", help="报表详情")
|
|
215
|
+
chart_subparsers = chart.add_subparsers(dest="builder_chart_command", required=True)
|
|
216
|
+
chart_get = chart_subparsers.add_parser("get", help="读取报表详情和数据")
|
|
217
|
+
chart_get.add_argument("--chart-id", required=True)
|
|
218
|
+
chart_get.add_argument("--data-payload-file")
|
|
219
|
+
chart_get.add_argument("--page-num", type=int)
|
|
220
|
+
chart_get.add_argument("--page-size", type=int)
|
|
221
|
+
chart_get.add_argument("--page-num-y", type=int)
|
|
222
|
+
chart_get.add_argument("--page-size-y", type=int)
|
|
223
|
+
chart_get.set_defaults(handler=_handle_chart_get, format_hint="builder_summary")
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _handle_package_list(args: argparse.Namespace, context: CliContext) -> dict:
|
|
227
|
+
return context.builder.package_list(profile=args.profile, trial_status=args.trial_status)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _handle_contract(args: argparse.Namespace, context: CliContext) -> dict:
|
|
231
|
+
return context.builder.builder_tool_contract(tool_name=args.tool_name)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def _handle_member_search(args: argparse.Namespace, context: CliContext) -> dict:
|
|
235
|
+
return context.builder.member_search(
|
|
236
|
+
profile=args.profile,
|
|
237
|
+
query=args.query,
|
|
238
|
+
page_num=args.page_num,
|
|
239
|
+
page_size=args.page_size,
|
|
240
|
+
contain_disable=bool(args.contain_disable),
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def _handle_role_search(args: argparse.Namespace, context: CliContext) -> dict:
|
|
245
|
+
return context.builder.role_search(
|
|
246
|
+
profile=args.profile,
|
|
247
|
+
keyword=args.keyword,
|
|
248
|
+
page_num=args.page_num,
|
|
249
|
+
page_size=args.page_size,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _handle_role_create(args: argparse.Namespace, context: CliContext) -> dict:
|
|
254
|
+
return context.builder.role_create(
|
|
255
|
+
profile=args.profile,
|
|
256
|
+
role_name=args.role_name,
|
|
257
|
+
member_uids=load_list_arg(args.member_uids_file, option_name="--member-uids-file"),
|
|
258
|
+
member_emails=load_list_arg(args.member_emails_file, option_name="--member-emails-file"),
|
|
259
|
+
member_names=load_list_arg(args.member_names_file, option_name="--member-names-file"),
|
|
260
|
+
role_icon=args.role_icon,
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _handle_package_resolve(args: argparse.Namespace, context: CliContext) -> dict:
|
|
265
|
+
return context.builder.package_resolve(profile=args.profile, package_name=args.package_name)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _handle_package_create(args: argparse.Namespace, context: CliContext) -> dict:
|
|
269
|
+
return context.builder.package_create(
|
|
270
|
+
profile=args.profile,
|
|
271
|
+
package_name=args.package_name,
|
|
272
|
+
icon=args.icon,
|
|
273
|
+
color=args.color,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _handle_package_attach_app(args: argparse.Namespace, context: CliContext) -> dict:
|
|
278
|
+
if (args.legacy_app_title or "").strip():
|
|
279
|
+
raise_config_error(
|
|
280
|
+
"package attach-app no longer accepts app_title.",
|
|
281
|
+
fix_hint="Use `--app-key` to identify the app to attach.",
|
|
282
|
+
)
|
|
283
|
+
return context.builder.package_attach_app(
|
|
284
|
+
profile=args.profile,
|
|
285
|
+
tag_id=args.tag_id,
|
|
286
|
+
app_key=args.app_key,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def _handle_app_resolve(args: argparse.Namespace, context: CliContext) -> dict:
|
|
291
|
+
has_app_key = bool((args.app_key or "").strip())
|
|
292
|
+
has_app_name = bool((args.app_name or "").strip())
|
|
293
|
+
has_package_tag_id = args.package_tag_id is not None
|
|
294
|
+
if has_app_key and (has_app_name or has_package_tag_id):
|
|
295
|
+
raise_config_error(
|
|
296
|
+
"app resolve accepts exactly one selector mode.",
|
|
297
|
+
fix_hint="Use only `--app-key`, or use `--app-name` together with `--package-tag-id`.",
|
|
298
|
+
)
|
|
299
|
+
if not has_app_key and not (has_app_name and has_package_tag_id):
|
|
300
|
+
raise_config_error(
|
|
301
|
+
"app resolve requires either --app-key, or --app-name together with --package-tag-id.",
|
|
302
|
+
fix_hint="For an existing known app, pass `--app-key`. For package-scoped lookup, pass both `--app-name` and `--package-tag-id`.",
|
|
303
|
+
)
|
|
304
|
+
return context.builder.app_resolve(
|
|
305
|
+
profile=args.profile,
|
|
306
|
+
app_key=args.app_key,
|
|
307
|
+
app_name=args.app_name,
|
|
308
|
+
package_tag_id=args.package_tag_id,
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def _handle_app_release_edit_lock_if_mine(args: argparse.Namespace, context: CliContext) -> dict:
|
|
313
|
+
return context.builder.app_release_edit_lock_if_mine(
|
|
314
|
+
profile=args.profile,
|
|
315
|
+
app_key=args.app_key,
|
|
316
|
+
lock_owner_email=args.lock_owner_email,
|
|
317
|
+
lock_owner_name=args.lock_owner_name,
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _handle_button_list(args: argparse.Namespace, context: CliContext) -> dict:
|
|
322
|
+
return context.builder.app_custom_button_list(profile=args.profile, app_key=args.app_key)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def _handle_button_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
326
|
+
return context.builder.app_custom_button_get(profile=args.profile, app_key=args.app_key, button_id=args.button_id)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def _handle_button_create(args: argparse.Namespace, context: CliContext) -> dict:
|
|
330
|
+
return context.builder.app_custom_button_create(
|
|
331
|
+
profile=args.profile,
|
|
332
|
+
app_key=args.app_key,
|
|
333
|
+
payload=load_object_arg(args.payload_file, option_name="--payload-file"),
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def _handle_button_update(args: argparse.Namespace, context: CliContext) -> dict:
|
|
338
|
+
return context.builder.app_custom_button_update(
|
|
339
|
+
profile=args.profile,
|
|
340
|
+
app_key=args.app_key,
|
|
341
|
+
button_id=args.button_id,
|
|
342
|
+
payload=load_object_arg(args.payload_file, option_name="--payload-file"),
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _handle_button_delete(args: argparse.Namespace, context: CliContext) -> dict:
|
|
347
|
+
return context.builder.app_custom_button_delete(profile=args.profile, app_key=args.app_key, button_id=args.button_id)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def _handle_app_read_summary(args: argparse.Namespace, context: CliContext) -> dict:
|
|
351
|
+
return context.builder.app_read_summary(profile=args.profile, app_key=args.app_key)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _handle_app_read_fields(args: argparse.Namespace, context: CliContext) -> dict:
|
|
355
|
+
return context.builder.app_read_fields(profile=args.profile, app_key=args.app_key)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def _handle_app_read_layout(args: argparse.Namespace, context: CliContext) -> dict:
|
|
359
|
+
return context.builder.app_read_layout_summary(profile=args.profile, app_key=args.app_key)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def _handle_app_read_views(args: argparse.Namespace, context: CliContext) -> dict:
|
|
363
|
+
return context.builder.app_read_views_summary(profile=args.profile, app_key=args.app_key)
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def _handle_app_read_flow(args: argparse.Namespace, context: CliContext) -> dict:
|
|
367
|
+
return context.builder.app_read_flow_summary(profile=args.profile, app_key=args.app_key)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def _handle_app_read_charts(args: argparse.Namespace, context: CliContext) -> dict:
|
|
371
|
+
return context.builder.app_read_charts_summary(profile=args.profile, app_key=args.app_key)
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def _handle_portal_list(args: argparse.Namespace, context: CliContext) -> dict:
|
|
375
|
+
return context.builder.portal_list(profile=args.profile)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def _handle_portal_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
379
|
+
return context.builder.portal_get(profile=args.profile, dash_key=args.dash_key, being_draft=bool(args.being_draft))
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def _handle_portal_read_summary(args: argparse.Namespace, context: CliContext) -> dict:
|
|
383
|
+
return context.builder.portal_read_summary(
|
|
384
|
+
profile=args.profile,
|
|
385
|
+
dash_key=args.dash_key,
|
|
386
|
+
being_draft=bool(args.being_draft),
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def _handle_view_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
391
|
+
return context.builder.view_get(profile=args.profile, viewgraph_key=args.viewgraph_key)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def _handle_chart_get(args: argparse.Namespace, context: CliContext) -> dict:
|
|
395
|
+
return context.builder.chart_get(
|
|
396
|
+
profile=args.profile,
|
|
397
|
+
chart_id=args.chart_id,
|
|
398
|
+
data_payload=load_object_arg(args.data_payload_file, option_name="--data-payload-file") if args.data_payload_file else {},
|
|
399
|
+
page_num=args.page_num,
|
|
400
|
+
page_size=args.page_size,
|
|
401
|
+
page_num_y=args.page_num_y,
|
|
402
|
+
page_size_y=args.page_size_y,
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def _handle_schema_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
407
|
+
has_app_key = bool((args.app_key or "").strip())
|
|
408
|
+
has_app_name = bool((args.app_name or "").strip())
|
|
409
|
+
has_app_title = bool((args.app_title or "").strip())
|
|
410
|
+
has_package_tag_id = args.package_tag_id is not None
|
|
411
|
+
if has_app_key:
|
|
412
|
+
if args.create_if_missing or has_app_name or has_package_tag_id or has_app_title:
|
|
413
|
+
raise_config_error(
|
|
414
|
+
"schema apply edit mode only accepts --app-key as the resource selector.",
|
|
415
|
+
fix_hint="For existing apps, pass `--app-key` only. For create mode, use `--package-tag-id --app-name --create-if-missing`.",
|
|
416
|
+
)
|
|
417
|
+
else:
|
|
418
|
+
if not args.create_if_missing or not has_package_tag_id or not has_app_name:
|
|
419
|
+
raise_config_error(
|
|
420
|
+
"schema apply create mode requires --package-tag-id, --app-name, and --create-if-missing.",
|
|
421
|
+
fix_hint="Use `--app-key` for existing apps, or pass `--package-tag-id --app-name --create-if-missing` to create a new app.",
|
|
422
|
+
)
|
|
423
|
+
return context.builder.app_schema_apply(
|
|
424
|
+
profile=args.profile,
|
|
425
|
+
app_key=args.app_key,
|
|
426
|
+
package_tag_id=args.package_tag_id,
|
|
427
|
+
app_name=args.app_name,
|
|
428
|
+
app_title=args.app_title,
|
|
429
|
+
icon=args.icon,
|
|
430
|
+
color=args.color,
|
|
431
|
+
create_if_missing=bool(args.create_if_missing),
|
|
432
|
+
publish=bool(args.publish),
|
|
433
|
+
add_fields=load_list_arg(args.add_fields_file, option_name="--add-fields-file"),
|
|
434
|
+
update_fields=load_list_arg(args.update_fields_file, option_name="--update-fields-file"),
|
|
435
|
+
remove_fields=load_list_arg(args.remove_fields_file, option_name="--remove-fields-file"),
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def _handle_layout_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
440
|
+
return context.builder.app_layout_apply(
|
|
441
|
+
profile=args.profile,
|
|
442
|
+
app_key=args.app_key,
|
|
443
|
+
mode=args.mode,
|
|
444
|
+
publish=bool(args.publish),
|
|
445
|
+
sections=require_list_arg(args.sections_file, option_name="--sections-file"),
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def _handle_views_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
450
|
+
return context.builder.app_views_apply(
|
|
451
|
+
profile=args.profile,
|
|
452
|
+
app_key=args.app_key,
|
|
453
|
+
publish=bool(args.publish),
|
|
454
|
+
upsert_views=load_list_arg(args.upsert_views_file, option_name="--upsert-views-file"),
|
|
455
|
+
remove_views=load_list_arg(args.remove_views_file, option_name="--remove-views-file"),
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def _handle_flow_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
460
|
+
return context.builder.app_flow_apply(
|
|
461
|
+
profile=args.profile,
|
|
462
|
+
app_key=args.app_key,
|
|
463
|
+
mode=args.mode,
|
|
464
|
+
publish=bool(args.publish),
|
|
465
|
+
nodes=require_list_arg(args.nodes_file, option_name="--nodes-file"),
|
|
466
|
+
transitions=require_list_arg(args.transitions_file, option_name="--transitions-file"),
|
|
467
|
+
)
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
def _handle_charts_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
471
|
+
return context.builder.app_charts_apply(
|
|
472
|
+
profile=args.profile,
|
|
473
|
+
app_key=args.app_key,
|
|
474
|
+
upsert_charts=load_list_arg(args.upsert_file, option_name="--upsert-file"),
|
|
475
|
+
remove_chart_ids=load_list_arg(args.remove_chart_ids_file, option_name="--remove-chart-ids-file"),
|
|
476
|
+
reorder_chart_ids=load_list_arg(args.reorder_chart_ids_file, option_name="--reorder-chart-ids-file"),
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def _handle_portal_apply(args: argparse.Namespace, context: CliContext) -> dict:
|
|
481
|
+
has_dash_key = bool((args.dash_key or "").strip())
|
|
482
|
+
has_dash_name = bool((args.dash_name or "").strip())
|
|
483
|
+
has_package_tag_id = args.package_tag_id is not None
|
|
484
|
+
if has_dash_key and has_package_tag_id:
|
|
485
|
+
raise_config_error(
|
|
486
|
+
"portal apply accepts exactly one selector mode.",
|
|
487
|
+
fix_hint="Use `--dash-key` to update an existing portal, or use `--package-tag-id --dash-name` to create a new portal.",
|
|
488
|
+
)
|
|
489
|
+
if not has_dash_key and not (has_package_tag_id and has_dash_name):
|
|
490
|
+
raise_config_error(
|
|
491
|
+
"portal apply requires either --dash-key, or --package-tag-id together with --dash-name.",
|
|
492
|
+
fix_hint="Use `--dash-key` for an existing portal. For create mode, pass `--package-tag-id --dash-name`.",
|
|
493
|
+
)
|
|
494
|
+
return context.builder.portal_apply(
|
|
495
|
+
profile=args.profile,
|
|
496
|
+
dash_key=args.dash_key,
|
|
497
|
+
dash_name=args.dash_name,
|
|
498
|
+
package_tag_id=args.package_tag_id,
|
|
499
|
+
publish=bool(args.publish),
|
|
500
|
+
sections=require_list_arg(args.sections_file, option_name="--sections-file"),
|
|
501
|
+
auth=load_object_arg(args.auth_file, option_name="--auth-file"),
|
|
502
|
+
icon=args.icon,
|
|
503
|
+
color=args.color,
|
|
504
|
+
hide_copyright=args.hide_copyright,
|
|
505
|
+
dash_global_config=load_object_arg(args.dash_global_config_file, option_name="--dash-global-config-file"),
|
|
506
|
+
config=load_object_arg(args.config_file, option_name="--config-file"),
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
def _handle_publish_verify(args: argparse.Namespace, context: CliContext) -> dict:
|
|
511
|
+
return context.builder.app_publish_verify(
|
|
512
|
+
profile=args.profile,
|
|
513
|
+
app_key=args.app_key,
|
|
514
|
+
expected_package_tag_id=args.expected_package_tag_id,
|
|
515
|
+
)
|