@qingflow-tech/qingflow-app-user-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +37 -0
  2. package/docs/local-agent-install.md +332 -0
  3. package/entry_point.py +13 -0
  4. package/npm/bin/qingflow-app-user-mcp.mjs +7 -0
  5. package/npm/lib/runtime.mjs +339 -0
  6. package/npm/scripts/postinstall.mjs +16 -0
  7. package/package.json +34 -0
  8. package/pyproject.toml +67 -0
  9. package/qingflow-app-user-mcp +15 -0
  10. package/skills/qingflow-app-user/SKILL.md +79 -0
  11. package/skills/qingflow-app-user/agents/openai.yaml +4 -0
  12. package/skills/qingflow-app-user/references/data-gotchas.md +29 -0
  13. package/skills/qingflow-app-user/references/environments.md +63 -0
  14. package/skills/qingflow-app-user/references/record-patterns.md +48 -0
  15. package/skills/qingflow-app-user/references/workflow-usage.md +26 -0
  16. package/skills/qingflow-record-analysis/SKILL.md +158 -0
  17. package/skills/qingflow-record-analysis/agents/openai.yaml +4 -0
  18. package/skills/qingflow-record-analysis/references/analysis-gotchas.md +145 -0
  19. package/skills/qingflow-record-analysis/references/analysis-patterns.md +125 -0
  20. package/skills/qingflow-record-analysis/references/confidence-reporting.md +92 -0
  21. package/skills/qingflow-record-analysis/references/dsl-templates.md +93 -0
  22. package/skills/qingflow-record-delete/SKILL.md +29 -0
  23. package/skills/qingflow-record-import/SKILL.md +31 -0
  24. package/skills/qingflow-record-insert/SKILL.md +58 -0
  25. package/skills/qingflow-record-update/SKILL.md +42 -0
  26. package/skills/qingflow-task-ops/SKILL.md +123 -0
  27. package/skills/qingflow-task-ops/agents/openai.yaml +4 -0
  28. package/skills/qingflow-task-ops/references/environments.md +44 -0
  29. package/skills/qingflow-task-ops/references/workflow-usage.md +27 -0
  30. package/src/qingflow_mcp/__init__.py +5 -0
  31. package/src/qingflow_mcp/__main__.py +5 -0
  32. package/src/qingflow_mcp/backend_client.py +649 -0
  33. package/src/qingflow_mcp/builder_facade/__init__.py +3 -0
  34. package/src/qingflow_mcp/builder_facade/models.py +1836 -0
  35. package/src/qingflow_mcp/builder_facade/service.py +15044 -0
  36. package/src/qingflow_mcp/cli/__init__.py +1 -0
  37. package/src/qingflow_mcp/cli/commands/__init__.py +18 -0
  38. package/src/qingflow_mcp/cli/commands/app.py +40 -0
  39. package/src/qingflow_mcp/cli/commands/auth.py +44 -0
  40. package/src/qingflow_mcp/cli/commands/builder.py +538 -0
  41. package/src/qingflow_mcp/cli/commands/chart.py +18 -0
  42. package/src/qingflow_mcp/cli/commands/common.py +62 -0
  43. package/src/qingflow_mcp/cli/commands/imports.py +96 -0
  44. package/src/qingflow_mcp/cli/commands/portal.py +25 -0
  45. package/src/qingflow_mcp/cli/commands/record.py +331 -0
  46. package/src/qingflow_mcp/cli/commands/repo.py +80 -0
  47. package/src/qingflow_mcp/cli/commands/task.py +89 -0
  48. package/src/qingflow_mcp/cli/commands/view.py +18 -0
  49. package/src/qingflow_mcp/cli/commands/workspace.py +25 -0
  50. package/src/qingflow_mcp/cli/context.py +60 -0
  51. package/src/qingflow_mcp/cli/formatters.py +334 -0
  52. package/src/qingflow_mcp/cli/json_io.py +50 -0
  53. package/src/qingflow_mcp/cli/main.py +178 -0
  54. package/src/qingflow_mcp/config.py +513 -0
  55. package/src/qingflow_mcp/errors.py +66 -0
  56. package/src/qingflow_mcp/import_store.py +121 -0
  57. package/src/qingflow_mcp/json_types.py +18 -0
  58. package/src/qingflow_mcp/list_type_labels.py +76 -0
  59. package/src/qingflow_mcp/public_surface.py +233 -0
  60. package/src/qingflow_mcp/repository_store.py +71 -0
  61. package/src/qingflow_mcp/response_trim.py +470 -0
  62. package/src/qingflow_mcp/server.py +212 -0
  63. package/src/qingflow_mcp/server_app_builder.py +533 -0
  64. package/src/qingflow_mcp/server_app_user.py +362 -0
  65. package/src/qingflow_mcp/session_store.py +302 -0
  66. package/src/qingflow_mcp/solution/__init__.py +6 -0
  67. package/src/qingflow_mcp/solution/build_assembly_store.py +181 -0
  68. package/src/qingflow_mcp/solution/compiler/__init__.py +282 -0
  69. package/src/qingflow_mcp/solution/compiler/chart_compiler.py +96 -0
  70. package/src/qingflow_mcp/solution/compiler/form_compiler.py +495 -0
  71. package/src/qingflow_mcp/solution/compiler/icon_utils.py +187 -0
  72. package/src/qingflow_mcp/solution/compiler/navigation_compiler.py +57 -0
  73. package/src/qingflow_mcp/solution/compiler/package_compiler.py +19 -0
  74. package/src/qingflow_mcp/solution/compiler/portal_compiler.py +60 -0
  75. package/src/qingflow_mcp/solution/compiler/view_compiler.py +51 -0
  76. package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +173 -0
  77. package/src/qingflow_mcp/solution/design_session.py +222 -0
  78. package/src/qingflow_mcp/solution/design_store.py +100 -0
  79. package/src/qingflow_mcp/solution/executor.py +2398 -0
  80. package/src/qingflow_mcp/solution/normalizer.py +23 -0
  81. package/src/qingflow_mcp/solution/requirements_builder.py +536 -0
  82. package/src/qingflow_mcp/solution/run_store.py +244 -0
  83. package/src/qingflow_mcp/solution/spec_models.py +855 -0
  84. package/src/qingflow_mcp/tools/__init__.py +1 -0
  85. package/src/qingflow_mcp/tools/ai_builder_tools.py +3419 -0
  86. package/src/qingflow_mcp/tools/app_tools.py +925 -0
  87. package/src/qingflow_mcp/tools/approval_tools.py +1062 -0
  88. package/src/qingflow_mcp/tools/auth_tools.py +875 -0
  89. package/src/qingflow_mcp/tools/base.py +388 -0
  90. package/src/qingflow_mcp/tools/code_block_tools.py +777 -0
  91. package/src/qingflow_mcp/tools/custom_button_tools.py +202 -0
  92. package/src/qingflow_mcp/tools/directory_tools.py +675 -0
  93. package/src/qingflow_mcp/tools/feedback_tools.py +238 -0
  94. package/src/qingflow_mcp/tools/file_tools.py +409 -0
  95. package/src/qingflow_mcp/tools/import_tools.py +2189 -0
  96. package/src/qingflow_mcp/tools/navigation_tools.py +210 -0
  97. package/src/qingflow_mcp/tools/package_tools.py +326 -0
  98. package/src/qingflow_mcp/tools/portal_tools.py +158 -0
  99. package/src/qingflow_mcp/tools/qingbi_report_tools.py +374 -0
  100. package/src/qingflow_mcp/tools/record_tools.py +14037 -0
  101. package/src/qingflow_mcp/tools/repository_dev_tools.py +552 -0
  102. package/src/qingflow_mcp/tools/resource_read_tools.py +421 -0
  103. package/src/qingflow_mcp/tools/role_tools.py +112 -0
  104. package/src/qingflow_mcp/tools/solution_tools.py +4054 -0
  105. package/src/qingflow_mcp/tools/task_context_tools.py +2228 -0
  106. package/src/qingflow_mcp/tools/task_tools.py +890 -0
  107. package/src/qingflow_mcp/tools/view_tools.py +335 -0
  108. package/src/qingflow_mcp/tools/workflow_tools.py +376 -0
  109. package/src/qingflow_mcp/tools/workspace_tools.py +125 -0
@@ -0,0 +1 @@
1
+ __all__: list[str] = []
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+
5
+ from . import app, auth, builder, chart, imports, portal, record, task, view, 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
+ portal.register(subparsers)
13
+ view.register(subparsers)
14
+ chart.register(subparsers)
15
+ record.register(subparsers)
16
+ imports.register(subparsers)
17
+ task.register(subparsers)
18
+ 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,44 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+
5
+ from ..context import CliContext
6
+ from .common import read_secret_arg
7
+
8
+
9
+ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
10
+ parser = subparsers.add_parser("auth", help="认证与会话")
11
+ auth_subparsers = parser.add_subparsers(dest="auth_command", required=True)
12
+
13
+ use_credential = auth_subparsers.add_parser("use-credential", help="直接注入 credential")
14
+ use_credential.add_argument("--base-url")
15
+ use_credential.add_argument("--qf-version")
16
+ use_credential.add_argument("--credential")
17
+ use_credential.add_argument("--credential-stdin", action="store_true")
18
+ use_credential.add_argument("--persist", action=argparse.BooleanOptionalAction, default=False)
19
+ use_credential.set_defaults(handler=_handle_use_credential, format_hint="auth_whoami")
20
+
21
+ whoami = auth_subparsers.add_parser("whoami", help="查看当前登录态")
22
+ whoami.set_defaults(handler=_handle_whoami, format_hint="auth_whoami")
23
+
24
+ logout = auth_subparsers.add_parser("logout", help="退出登录")
25
+ logout.add_argument("--forget-persisted", action="store_true")
26
+ logout.set_defaults(handler=_handle_logout, format_hint="")
27
+
28
+ def _handle_use_credential(args: argparse.Namespace, context: CliContext) -> dict:
29
+ credential = read_secret_arg(args.credential, stdin_enabled=bool(args.credential_stdin), label="credential")
30
+ return context.auth.auth_use_credential(
31
+ profile=args.profile,
32
+ base_url=args.base_url,
33
+ qf_version=args.qf_version,
34
+ credential=credential,
35
+ persist=bool(args.persist),
36
+ )
37
+
38
+
39
+ def _handle_whoami(args: argparse.Namespace, context: CliContext) -> dict:
40
+ return context.auth.auth_whoami(profile=args.profile)
41
+
42
+
43
+ def _handle_logout(args: argparse.Namespace, context: CliContext) -> dict:
44
+ return context.auth.auth_logout(profile=args.profile, forget_persisted=bool(args.forget_persisted))
@@ -0,0 +1,538 @@
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
+ file_parser = builder_subparsers.add_parser("file", help="builder 侧文件上传")
14
+ file_subparsers = file_parser.add_subparsers(dest="builder_file_command", required=True)
15
+ file_upload_local = file_subparsers.add_parser("upload-local", help="上传本地文件并返回附件值")
16
+ file_upload_local.add_argument("--upload-kind", default="attachment")
17
+ file_upload_local.add_argument("--file-path", required=True)
18
+ file_upload_local.add_argument("--upload-mark")
19
+ file_upload_local.add_argument("--content-type")
20
+ file_upload_local.add_argument("--bucket-type")
21
+ file_upload_local.add_argument("--path-id", type=int)
22
+ file_upload_local.add_argument("--file-related-url")
23
+ file_upload_local.set_defaults(handler=_handle_file_upload_local, format_hint="generic")
24
+
25
+ feedback = builder_subparsers.add_parser("feedback", help="builder 侧反馈提交")
26
+ feedback_subparsers = feedback.add_subparsers(dest="builder_feedback_command", required=True)
27
+ feedback_submit = feedback_subparsers.add_parser("submit", help="提交 builder 能力反馈")
28
+ feedback_submit.add_argument("--category", required=True)
29
+ feedback_submit.add_argument("--title", required=True)
30
+ feedback_submit.add_argument("--description", required=True)
31
+ feedback_submit.add_argument("--expected-behavior")
32
+ feedback_submit.add_argument("--actual-behavior")
33
+ feedback_submit.add_argument("--impact-scope")
34
+ feedback_submit.add_argument("--tool-name")
35
+ feedback_submit.add_argument("--app-key")
36
+ feedback_submit.add_argument("--record-id")
37
+ feedback_submit.add_argument("--workflow-node-id")
38
+ feedback_submit.add_argument("--note")
39
+ feedback_submit.set_defaults(handler=_handle_feedback_submit, format_hint="generic")
40
+
41
+ contract = builder_subparsers.add_parser("contract", help="读取 builder tool 合约")
42
+ contract.add_argument("--tool-name", required=True)
43
+ contract.set_defaults(handler=_handle_contract, format_hint="builder_summary")
44
+
45
+ member = builder_subparsers.add_parser("member", help="成员目录")
46
+ member_subparsers = member.add_subparsers(dest="builder_member_command", required=True)
47
+ member_search = member_subparsers.add_parser("search", help="搜索成员")
48
+ member_search.add_argument("--query", default="")
49
+ member_search.add_argument("--page-num", type=int, default=1)
50
+ member_search.add_argument("--page-size", type=int, default=20)
51
+ member_search.add_argument("--contain-disable", action=argparse.BooleanOptionalAction, default=False)
52
+ member_search.set_defaults(handler=_handle_member_search, format_hint="builder_summary")
53
+
54
+ role = builder_subparsers.add_parser("role", help="角色目录")
55
+ role_subparsers = role.add_subparsers(dest="builder_role_command", required=True)
56
+ role_search = role_subparsers.add_parser("search", help="搜索角色")
57
+ role_search.add_argument("--keyword", default="")
58
+ role_search.add_argument("--page-num", type=int, default=1)
59
+ role_search.add_argument("--page-size", type=int, default=20)
60
+ role_search.set_defaults(handler=_handle_role_search, format_hint="builder_summary")
61
+
62
+ role_create = role_subparsers.add_parser("create", help="创建角色")
63
+ role_create.add_argument("--role-name", required=True)
64
+ role_create.add_argument("--member-uids-file")
65
+ role_create.add_argument("--member-emails-file")
66
+ role_create.add_argument("--member-names-file")
67
+ role_create.add_argument("--role-icon", default="ex-user-outlined")
68
+ role_create.set_defaults(handler=_handle_role_create, format_hint="builder_summary")
69
+
70
+ package = builder_subparsers.add_parser("package", help="应用包")
71
+ package_subparsers = package.add_subparsers(dest="builder_package_command", required=True)
72
+
73
+ solution = builder_subparsers.add_parser("solution", help="解决方案")
74
+ solution_subparsers = solution.add_subparsers(dest="builder_solution_command", required=True)
75
+ solution_install = solution_subparsers.add_parser("install", help="安装解决方案")
76
+ solution_install.add_argument("--solution-key", required=True)
77
+ solution_install.add_argument("--being-copy-data", action=argparse.BooleanOptionalAction, default=True)
78
+ solution_install.add_argument("--solution-source", default="solutionDetail")
79
+ solution_install.set_defaults(handler=_handle_solution_install, format_hint="builder_summary")
80
+
81
+ package_get = package_subparsers.add_parser("get", help="读取应用包详情")
82
+ package_get.add_argument("--package-id", type=int, required=True)
83
+ package_get.set_defaults(handler=_handle_package_get, format_hint="builder_summary")
84
+
85
+ package_apply = package_subparsers.add_parser("apply", help="创建或更新应用包配置")
86
+ package_apply.add_argument("--config-file", required=True)
87
+ package_apply.set_defaults(handler=_handle_package_apply, format_hint="builder_summary")
88
+
89
+ app = builder_subparsers.add_parser("app", help="应用")
90
+ app_subparsers = app.add_subparsers(dest="builder_app_command", required=True)
91
+
92
+ app_resolve = app_subparsers.add_parser("resolve", help="解析应用")
93
+ app_resolve.add_argument("--app-key", default="")
94
+ app_resolve.add_argument("--app-name", default="")
95
+ app_resolve.add_argument("--package-id", type=int)
96
+ app_resolve.set_defaults(handler=_handle_app_resolve, format_hint="builder_summary")
97
+
98
+ app_release_lock = app_subparsers.add_parser("release-edit-lock-if-mine", help="释放当前账号持有的编辑锁")
99
+ app_release_lock.add_argument("--app-key", required=True)
100
+ app_release_lock.add_argument("--lock-owner-email", required=True)
101
+ 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")
103
+
104
+ app_get = app_subparsers.add_parser("get", help="读取应用配置")
105
+ app_get.add_argument(
106
+ "builder_app_get_section",
107
+ nargs="?",
108
+ choices=["summary", "fields", "layout", "views", "flow", "charts"],
109
+ default="summary",
110
+ )
111
+ app_get.add_argument("--app-key", required=True)
112
+ app_get.set_defaults(handler=_handle_app_get, format_hint="builder_summary")
113
+
114
+ app_repair_code_blocks = app_subparsers.add_parser("repair-code-blocks", help="扫描或修复现有代码块配置")
115
+ app_repair_code_blocks.add_argument("--app-key", required=True)
116
+ app_repair_code_blocks.add_argument("--field")
117
+ app_repair_code_blocks.add_argument("--apply", action="store_true")
118
+ app_repair_code_blocks.set_defaults(handler=_handle_app_repair_code_blocks, format_hint="builder_summary")
119
+
120
+ button = builder_subparsers.add_parser("button", help="自定义按钮")
121
+ button_subparsers = button.add_subparsers(dest="builder_button_command", required=True)
122
+
123
+ button_list = button_subparsers.add_parser("list", help="列出自定义按钮")
124
+ button_list.add_argument("--app-key", required=True)
125
+ button_list.set_defaults(handler=_handle_button_list, format_hint="builder_summary")
126
+
127
+ button_get = button_subparsers.add_parser("get", help="读取自定义按钮")
128
+ button_get.add_argument("--app-key", required=True)
129
+ button_get.add_argument("--button-id", type=int, required=True)
130
+ button_get.set_defaults(handler=_handle_button_get, format_hint="builder_summary")
131
+
132
+ button_create = button_subparsers.add_parser("create", help="创建自定义按钮")
133
+ button_create.add_argument("--app-key", required=True)
134
+ button_create.add_argument("--payload-file", required=True)
135
+ button_create.set_defaults(handler=_handle_button_create, format_hint="builder_summary")
136
+
137
+ button_update = button_subparsers.add_parser("update", help="更新自定义按钮")
138
+ button_update.add_argument("--app-key", required=True)
139
+ button_update.add_argument("--button-id", type=int, required=True)
140
+ button_update.add_argument("--payload-file", required=True)
141
+ button_update.set_defaults(handler=_handle_button_update, format_hint="builder_summary")
142
+
143
+ button_delete = button_subparsers.add_parser("delete", help="删除自定义按钮")
144
+ button_delete.add_argument("--app-key", required=True)
145
+ button_delete.add_argument("--button-id", type=int, required=True)
146
+ button_delete.set_defaults(handler=_handle_button_delete, format_hint="builder_summary")
147
+
148
+ portal = builder_subparsers.add_parser("portal", help="门户")
149
+ portal_subparsers = portal.add_subparsers(dest="builder_portal_command", required=True)
150
+ portal_list = portal_subparsers.add_parser("list", help="列出可配置门户")
151
+ portal_list.set_defaults(handler=_handle_portal_list, format_hint="builder_summary")
152
+
153
+ portal_get = portal_subparsers.add_parser("get", help="读取门户详情")
154
+ portal_get.add_argument("--dash-key", required=True)
155
+ portal_get.add_argument("--being-draft", action=argparse.BooleanOptionalAction, default=True)
156
+ portal_get.set_defaults(handler=_handle_portal_get, format_hint="builder_summary")
157
+
158
+ portal_apply = portal_subparsers.add_parser("apply", help="更新门户")
159
+ portal_apply.add_argument("--dash-key", default="")
160
+ portal_apply.add_argument("--dash-name", default="")
161
+ portal_apply.add_argument("--package-id", type=int)
162
+ portal_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
163
+ portal_apply.add_argument("--sections-file", required=True)
164
+ portal_apply.add_argument("--visibility-file")
165
+ portal_apply.add_argument("--auth-file")
166
+ portal_apply.add_argument("--icon")
167
+ portal_apply.add_argument("--color")
168
+ portal_apply.add_argument("--hide-copyright", action=argparse.BooleanOptionalAction, default=None)
169
+ portal_apply.add_argument("--dash-global-config-file")
170
+ portal_apply.add_argument("--config-file")
171
+ portal_apply.set_defaults(handler=_handle_portal_apply, format_hint="builder_summary")
172
+
173
+ schema_apply = builder_subparsers.add_parser("schema", help="字段搭建")
174
+ schema_apply_subparsers = schema_apply.add_subparsers(dest="builder_schema_command", required=True)
175
+ schema_apply_apply = schema_apply_subparsers.add_parser("apply", help="执行字段变更")
176
+ schema_apply_apply.add_argument("--app-key", default="")
177
+ schema_apply_apply.add_argument("--package-id", type=int)
178
+ schema_apply_apply.add_argument("--app-name", default="")
179
+ schema_apply_apply.add_argument("--app-title", default="")
180
+ schema_apply_apply.add_argument("--icon")
181
+ schema_apply_apply.add_argument("--color")
182
+ schema_apply_apply.add_argument("--visibility-file")
183
+ schema_apply_apply.add_argument("--create-if-missing", action="store_true")
184
+ schema_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
185
+ schema_apply_apply.add_argument("--add-fields-file")
186
+ schema_apply_apply.add_argument("--update-fields-file")
187
+ schema_apply_apply.add_argument("--remove-fields-file")
188
+ schema_apply_apply.set_defaults(handler=_handle_schema_apply, format_hint="builder_summary")
189
+
190
+ layout_apply = builder_subparsers.add_parser("layout", help="布局")
191
+ layout_apply_subparsers = layout_apply.add_subparsers(dest="builder_layout_command", required=True)
192
+ layout_apply_apply = layout_apply_subparsers.add_parser("apply", help="执行布局变更")
193
+ layout_apply_apply.add_argument("--app-key", required=True)
194
+ layout_apply_apply.add_argument("--mode", choices=["merge", "replace"], default="merge")
195
+ layout_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
196
+ layout_apply_apply.add_argument("--sections-file", required=True)
197
+ layout_apply_apply.set_defaults(handler=_handle_layout_apply, format_hint="builder_summary")
198
+
199
+ views_apply = builder_subparsers.add_parser("views", help="视图")
200
+ views_apply_subparsers = views_apply.add_subparsers(dest="builder_views_command", required=True)
201
+ views_apply_apply = views_apply_subparsers.add_parser("apply", help="执行视图变更")
202
+ views_apply_apply.add_argument("--app-key", required=True)
203
+ views_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
204
+ views_apply_apply.add_argument("--upsert-views-file")
205
+ views_apply_apply.add_argument("--remove-views-file")
206
+ views_apply_apply.set_defaults(handler=_handle_views_apply, format_hint="builder_summary")
207
+
208
+ flow_apply = builder_subparsers.add_parser("flow", help="流程")
209
+ flow_apply_subparsers = flow_apply.add_subparsers(dest="builder_flow_command", required=True)
210
+ flow_apply_apply = flow_apply_subparsers.add_parser("apply", help="执行流程变更")
211
+ flow_apply_apply.add_argument("--app-key", required=True)
212
+ flow_apply_apply.add_argument("--mode", choices=["replace"], default="replace")
213
+ flow_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
214
+ flow_apply_apply.add_argument("--nodes-file", required=True)
215
+ flow_apply_apply.add_argument("--transitions-file", required=True)
216
+ flow_apply_apply.set_defaults(handler=_handle_flow_apply, format_hint="builder_summary")
217
+
218
+ charts_apply = builder_subparsers.add_parser("charts", help="报表")
219
+ charts_apply_subparsers = charts_apply.add_subparsers(dest="builder_charts_command", required=True)
220
+ charts_apply_apply = charts_apply_subparsers.add_parser("apply", help="执行报表变更")
221
+ charts_apply_apply.add_argument("--app-key", required=True)
222
+ charts_apply_apply.add_argument("--upsert-file")
223
+ charts_apply_apply.add_argument("--remove-chart-ids-file")
224
+ charts_apply_apply.add_argument("--reorder-chart-ids-file")
225
+ charts_apply_apply.set_defaults(handler=_handle_charts_apply, format_hint="builder_summary")
226
+
227
+ publish_verify = builder_subparsers.add_parser("publish", help="发布校验")
228
+ publish_verify_subparsers = publish_verify.add_subparsers(dest="builder_publish_command", required=True)
229
+ publish_verify_verify = publish_verify_subparsers.add_parser("verify", help="校验应用发布")
230
+ publish_verify_verify.add_argument("--app-key", required=True)
231
+ publish_verify_verify.add_argument("--expected-package-id", type=int)
232
+ publish_verify_verify.set_defaults(handler=_handle_publish_verify, format_hint="builder_summary")
233
+
234
+ view = builder_subparsers.add_parser("view", help="视图详情")
235
+ view_subparsers = view.add_subparsers(dest="builder_view_command", required=True)
236
+ view_get = view_subparsers.add_parser("get", help="读取视图详情")
237
+ view_get.add_argument("--view-key", required=True)
238
+ view_get.set_defaults(handler=_handle_view_get, format_hint="builder_summary")
239
+
240
+ chart = builder_subparsers.add_parser("chart", help="报表详情")
241
+ chart_subparsers = chart.add_subparsers(dest="builder_chart_command", required=True)
242
+ chart_get = chart_subparsers.add_parser("get", help="读取报表配置详情")
243
+ chart_get.add_argument("--chart-id", required=True)
244
+ chart_get.set_defaults(handler=_handle_chart_get, format_hint="builder_summary")
245
+
246
+
247
+ def _handle_file_upload_local(args: argparse.Namespace, context: CliContext) -> dict:
248
+ return context.files.file_upload_local(
249
+ profile=args.profile,
250
+ upload_kind=args.upload_kind,
251
+ file_path=args.file_path,
252
+ upload_mark=args.upload_mark,
253
+ content_type=args.content_type,
254
+ bucket_type=args.bucket_type,
255
+ path_id=args.path_id,
256
+ file_related_url=args.file_related_url,
257
+ )
258
+
259
+
260
+ def _handle_feedback_submit(args: argparse.Namespace, context: CliContext) -> dict:
261
+ return context.builder_feedback.feedback_submit(
262
+ category=args.category,
263
+ title=args.title,
264
+ description=args.description,
265
+ expected_behavior=args.expected_behavior,
266
+ actual_behavior=args.actual_behavior,
267
+ impact_scope=args.impact_scope,
268
+ tool_name=args.tool_name,
269
+ app_key=args.app_key,
270
+ record_id=args.record_id,
271
+ workflow_node_id=args.workflow_node_id,
272
+ note=args.note,
273
+ )
274
+
275
+
276
+ def _handle_contract(args: argparse.Namespace, context: CliContext) -> dict:
277
+ return context.builder.builder_tool_contract(tool_name=args.tool_name)
278
+
279
+
280
+ def _handle_member_search(args: argparse.Namespace, context: CliContext) -> dict:
281
+ return context.builder.member_search(
282
+ profile=args.profile,
283
+ query=args.query,
284
+ page_num=args.page_num,
285
+ page_size=args.page_size,
286
+ contain_disable=bool(args.contain_disable),
287
+ )
288
+
289
+
290
+ def _handle_role_search(args: argparse.Namespace, context: CliContext) -> dict:
291
+ return context.builder.role_search(
292
+ profile=args.profile,
293
+ keyword=args.keyword,
294
+ page_num=args.page_num,
295
+ page_size=args.page_size,
296
+ )
297
+
298
+
299
+ def _handle_role_create(args: argparse.Namespace, context: CliContext) -> dict:
300
+ return context.builder.role_create(
301
+ profile=args.profile,
302
+ role_name=args.role_name,
303
+ member_uids=load_list_arg(args.member_uids_file, option_name="--member-uids-file"),
304
+ member_emails=load_list_arg(args.member_emails_file, option_name="--member-emails-file"),
305
+ member_names=load_list_arg(args.member_names_file, option_name="--member-names-file"),
306
+ role_icon=args.role_icon,
307
+ )
308
+
309
+
310
+ def _handle_solution_install(args: argparse.Namespace, context: CliContext) -> dict:
311
+ return context.builder.solution_install(
312
+ profile=args.profile,
313
+ solution_key=args.solution_key,
314
+ being_copy_data=bool(args.being_copy_data),
315
+ solution_source=args.solution_source,
316
+ )
317
+
318
+
319
+ def _handle_package_get(args: argparse.Namespace, context: CliContext) -> dict:
320
+ return context.builder.package_get(profile=args.profile, package_id=args.package_id)
321
+
322
+
323
+ def _handle_package_apply(args: argparse.Namespace, context: CliContext) -> dict:
324
+ config = load_object_arg(args.config_file, option_name="--config-file")
325
+ if not isinstance(config, dict):
326
+ raise_config_error("package apply --config-file must contain a JSON object.")
327
+ return context.builder.package_apply(profile=args.profile, **config)
328
+
329
+
330
+ def _handle_app_resolve(args: argparse.Namespace, context: CliContext) -> dict:
331
+ has_app_key = bool((args.app_key or "").strip())
332
+ has_app_name = bool((args.app_name or "").strip())
333
+ has_package_id = args.package_id is not None
334
+ if has_app_key and (has_app_name or has_package_id):
335
+ raise_config_error(
336
+ "app resolve accepts exactly one selector mode.",
337
+ fix_hint="Use only `--app-key`, or use `--app-name` together with `--package-id`.",
338
+ )
339
+ if not has_app_key and not (has_app_name and has_package_id):
340
+ raise_config_error(
341
+ "app resolve requires either --app-key, or --app-name together with --package-id.",
342
+ fix_hint="For an existing known app, pass `--app-key`. For package-scoped lookup, pass both `--app-name` and `--package-id`.",
343
+ )
344
+ return context.builder.app_resolve(
345
+ profile=args.profile,
346
+ app_key=args.app_key,
347
+ app_name=args.app_name,
348
+ package_id=args.package_id,
349
+ )
350
+
351
+
352
+ def _handle_app_release_edit_lock_if_mine(args: argparse.Namespace, context: CliContext) -> dict:
353
+ return context.builder.app_release_edit_lock_if_mine(
354
+ profile=args.profile,
355
+ app_key=args.app_key,
356
+ lock_owner_email=args.lock_owner_email,
357
+ lock_owner_name=args.lock_owner_name,
358
+ )
359
+
360
+
361
+ def _handle_button_list(args: argparse.Namespace, context: CliContext) -> dict:
362
+ return context.builder.app_custom_button_list(profile=args.profile, app_key=args.app_key)
363
+
364
+
365
+ def _handle_button_get(args: argparse.Namespace, context: CliContext) -> dict:
366
+ return context.builder.app_custom_button_get(profile=args.profile, app_key=args.app_key, button_id=args.button_id)
367
+
368
+
369
+ def _handle_button_create(args: argparse.Namespace, context: CliContext) -> dict:
370
+ return context.builder.app_custom_button_create(
371
+ profile=args.profile,
372
+ app_key=args.app_key,
373
+ payload=load_object_arg(args.payload_file, option_name="--payload-file"),
374
+ )
375
+
376
+
377
+ def _handle_button_update(args: argparse.Namespace, context: CliContext) -> dict:
378
+ return context.builder.app_custom_button_update(
379
+ profile=args.profile,
380
+ app_key=args.app_key,
381
+ button_id=args.button_id,
382
+ payload=load_object_arg(args.payload_file, option_name="--payload-file"),
383
+ )
384
+
385
+
386
+ def _handle_button_delete(args: argparse.Namespace, context: CliContext) -> dict:
387
+ return context.builder.app_custom_button_delete(profile=args.profile, app_key=args.app_key, button_id=args.button_id)
388
+
389
+
390
+ def _handle_app_get(args: argparse.Namespace, context: CliContext) -> dict:
391
+ handlers = {
392
+ "summary": context.builder.app_get,
393
+ "fields": context.builder.app_get_fields,
394
+ "layout": context.builder.app_get_layout,
395
+ "views": context.builder.app_get_views,
396
+ "flow": context.builder.app_get_flow,
397
+ "charts": context.builder.app_get_charts,
398
+ }
399
+ return handlers[args.builder_app_get_section](profile=args.profile, app_key=args.app_key)
400
+
401
+
402
+ def _handle_app_repair_code_blocks(args: argparse.Namespace, context: CliContext) -> dict:
403
+ return context.builder.app_repair_code_blocks(
404
+ profile=args.profile,
405
+ app_key=args.app_key,
406
+ field=args.field,
407
+ apply=bool(args.apply),
408
+ )
409
+
410
+
411
+ def _handle_portal_list(args: argparse.Namespace, context: CliContext) -> dict:
412
+ return context.builder.portal_list(profile=args.profile)
413
+
414
+
415
+ def _handle_portal_get(args: argparse.Namespace, context: CliContext) -> dict:
416
+ return context.builder.portal_get(profile=args.profile, dash_key=args.dash_key, being_draft=bool(args.being_draft))
417
+
418
+
419
+ def _handle_view_get(args: argparse.Namespace, context: CliContext) -> dict:
420
+ return context.builder.view_get(profile=args.profile, view_key=args.view_key)
421
+
422
+
423
+ def _handle_chart_get(args: argparse.Namespace, context: CliContext) -> dict:
424
+ return context.builder.chart_get(profile=args.profile, chart_id=args.chart_id)
425
+
426
+
427
+ def _handle_schema_apply(args: argparse.Namespace, context: CliContext) -> dict:
428
+ has_app_key = bool((args.app_key or "").strip())
429
+ has_app_name = bool((args.app_name or "").strip())
430
+ has_app_title = bool((args.app_title or "").strip())
431
+ has_package_id = args.package_id is not None
432
+ if has_app_key:
433
+ if args.create_if_missing or has_package_id:
434
+ raise_config_error(
435
+ "schema apply edit mode accepts --app-key and optional --app-name only.",
436
+ fix_hint="For existing apps, use `--app-key` and optionally `--app-name`. For create mode, use `--package-id --app-name --create-if-missing`.",
437
+ )
438
+ else:
439
+ if not args.create_if_missing or not has_package_id or not (has_app_name or has_app_title):
440
+ raise_config_error(
441
+ "schema apply create mode requires --package-id, --app-name, and --create-if-missing.",
442
+ fix_hint="Use `--app-key` for existing apps, or pass `--package-id --app-name --create-if-missing` to create a new app.",
443
+ )
444
+ return context.builder.app_schema_apply(
445
+ profile=args.profile,
446
+ app_key=args.app_key,
447
+ package_id=args.package_id,
448
+ app_name=args.app_name,
449
+ app_title=args.app_title,
450
+ icon=args.icon,
451
+ color=args.color,
452
+ visibility=load_object_arg(args.visibility_file, option_name="--visibility-file"),
453
+ create_if_missing=bool(args.create_if_missing),
454
+ publish=bool(args.publish),
455
+ add_fields=load_list_arg(args.add_fields_file, option_name="--add-fields-file"),
456
+ update_fields=load_list_arg(args.update_fields_file, option_name="--update-fields-file"),
457
+ remove_fields=load_list_arg(args.remove_fields_file, option_name="--remove-fields-file"),
458
+ )
459
+
460
+
461
+ def _handle_layout_apply(args: argparse.Namespace, context: CliContext) -> dict:
462
+ return context.builder.app_layout_apply(
463
+ profile=args.profile,
464
+ app_key=args.app_key,
465
+ mode=args.mode,
466
+ publish=bool(args.publish),
467
+ sections=require_list_arg(args.sections_file, option_name="--sections-file"),
468
+ )
469
+
470
+
471
+ def _handle_views_apply(args: argparse.Namespace, context: CliContext) -> dict:
472
+ return context.builder.app_views_apply(
473
+ profile=args.profile,
474
+ app_key=args.app_key,
475
+ publish=bool(args.publish),
476
+ upsert_views=load_list_arg(args.upsert_views_file, option_name="--upsert-views-file"),
477
+ remove_views=load_list_arg(args.remove_views_file, option_name="--remove-views-file"),
478
+ )
479
+
480
+
481
+ def _handle_flow_apply(args: argparse.Namespace, context: CliContext) -> dict:
482
+ return context.builder.app_flow_apply(
483
+ profile=args.profile,
484
+ app_key=args.app_key,
485
+ mode=args.mode,
486
+ publish=bool(args.publish),
487
+ nodes=require_list_arg(args.nodes_file, option_name="--nodes-file"),
488
+ transitions=require_list_arg(args.transitions_file, option_name="--transitions-file"),
489
+ )
490
+
491
+
492
+ def _handle_charts_apply(args: argparse.Namespace, context: CliContext) -> dict:
493
+ return context.builder.app_charts_apply(
494
+ profile=args.profile,
495
+ app_key=args.app_key,
496
+ upsert_charts=load_list_arg(args.upsert_file, option_name="--upsert-file"),
497
+ remove_chart_ids=load_list_arg(args.remove_chart_ids_file, option_name="--remove-chart-ids-file"),
498
+ reorder_chart_ids=load_list_arg(args.reorder_chart_ids_file, option_name="--reorder-chart-ids-file"),
499
+ )
500
+
501
+
502
+ def _handle_portal_apply(args: argparse.Namespace, context: CliContext) -> dict:
503
+ has_dash_key = bool((args.dash_key or "").strip())
504
+ has_dash_name = bool((args.dash_name or "").strip())
505
+ has_package_id = args.package_id is not None
506
+ if has_dash_key and has_package_id:
507
+ raise_config_error(
508
+ "portal apply accepts exactly one selector mode.",
509
+ fix_hint="Use `--dash-key` to update an existing portal, or use `--package-id --dash-name` to create a new portal.",
510
+ )
511
+ if not has_dash_key and not (has_package_id and has_dash_name):
512
+ raise_config_error(
513
+ "portal apply requires either --dash-key, or --package-id together with --dash-name.",
514
+ fix_hint="Use `--dash-key` for an existing portal. For create mode, pass `--package-id --dash-name`.",
515
+ )
516
+ return context.builder.portal_apply(
517
+ profile=args.profile,
518
+ dash_key=args.dash_key,
519
+ dash_name=args.dash_name,
520
+ package_id=args.package_id,
521
+ publish=bool(args.publish),
522
+ sections=require_list_arg(args.sections_file, option_name="--sections-file"),
523
+ visibility=load_object_arg(args.visibility_file, option_name="--visibility-file"),
524
+ auth=load_object_arg(args.auth_file, option_name="--auth-file"),
525
+ icon=args.icon,
526
+ color=args.color,
527
+ hide_copyright=args.hide_copyright,
528
+ dash_global_config=load_object_arg(args.dash_global_config_file, option_name="--dash-global-config-file"),
529
+ config=load_object_arg(args.config_file, option_name="--config-file"),
530
+ )
531
+
532
+
533
+ def _handle_publish_verify(args: argparse.Namespace, context: CliContext) -> dict:
534
+ return context.builder.app_publish_verify(
535
+ profile=args.profile,
536
+ app_key=args.app_key,
537
+ expected_package_id=args.expected_package_id,
538
+ )
@@ -0,0 +1,18 @@
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("chart", help="报表访问")
10
+ chart_subparsers = parser.add_subparsers(dest="chart_command", required=True)
11
+
12
+ get_parser = chart_subparsers.add_parser("get", help="读取报表数据")
13
+ get_parser.add_argument("--chart-id", required=True)
14
+ get_parser.set_defaults(handler=_handle_get, format_hint="generic")
15
+
16
+
17
+ def _handle_get(args: argparse.Namespace, context: CliContext) -> dict:
18
+ return context.resource.chart_get(profile=args.profile, chart_id=args.chart_id)