@josephyan/qingflow-cli 0.2.0-beta.55

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 (79) hide show
  1. package/README.md +30 -0
  2. package/docs/local-agent-install.md +235 -0
  3. package/entry_point.py +13 -0
  4. package/npm/bin/qingflow.mjs +5 -0
  5. package/npm/lib/runtime.mjs +204 -0
  6. package/npm/scripts/postinstall.mjs +16 -0
  7. package/package.json +34 -0
  8. package/pyproject.toml +67 -0
  9. package/qingflow +15 -0
  10. package/src/qingflow_mcp/__init__.py +5 -0
  11. package/src/qingflow_mcp/__main__.py +5 -0
  12. package/src/qingflow_mcp/backend_client.py +547 -0
  13. package/src/qingflow_mcp/builder_facade/__init__.py +3 -0
  14. package/src/qingflow_mcp/builder_facade/models.py +985 -0
  15. package/src/qingflow_mcp/builder_facade/service.py +8243 -0
  16. package/src/qingflow_mcp/cli/__init__.py +1 -0
  17. package/src/qingflow_mcp/cli/commands/__init__.py +15 -0
  18. package/src/qingflow_mcp/cli/commands/app.py +40 -0
  19. package/src/qingflow_mcp/cli/commands/auth.py +78 -0
  20. package/src/qingflow_mcp/cli/commands/builder.py +184 -0
  21. package/src/qingflow_mcp/cli/commands/common.py +47 -0
  22. package/src/qingflow_mcp/cli/commands/imports.py +86 -0
  23. package/src/qingflow_mcp/cli/commands/record.py +202 -0
  24. package/src/qingflow_mcp/cli/commands/task.py +87 -0
  25. package/src/qingflow_mcp/cli/commands/workspace.py +33 -0
  26. package/src/qingflow_mcp/cli/context.py +48 -0
  27. package/src/qingflow_mcp/cli/formatters.py +269 -0
  28. package/src/qingflow_mcp/cli/json_io.py +50 -0
  29. package/src/qingflow_mcp/cli/main.py +147 -0
  30. package/src/qingflow_mcp/config.py +221 -0
  31. package/src/qingflow_mcp/errors.py +66 -0
  32. package/src/qingflow_mcp/import_store.py +121 -0
  33. package/src/qingflow_mcp/json_types.py +18 -0
  34. package/src/qingflow_mcp/list_type_labels.py +76 -0
  35. package/src/qingflow_mcp/server.py +211 -0
  36. package/src/qingflow_mcp/server_app_builder.py +387 -0
  37. package/src/qingflow_mcp/server_app_user.py +317 -0
  38. package/src/qingflow_mcp/session_store.py +289 -0
  39. package/src/qingflow_mcp/solution/__init__.py +6 -0
  40. package/src/qingflow_mcp/solution/build_assembly_store.py +181 -0
  41. package/src/qingflow_mcp/solution/compiler/__init__.py +282 -0
  42. package/src/qingflow_mcp/solution/compiler/chart_compiler.py +96 -0
  43. package/src/qingflow_mcp/solution/compiler/form_compiler.py +466 -0
  44. package/src/qingflow_mcp/solution/compiler/icon_utils.py +113 -0
  45. package/src/qingflow_mcp/solution/compiler/navigation_compiler.py +57 -0
  46. package/src/qingflow_mcp/solution/compiler/package_compiler.py +19 -0
  47. package/src/qingflow_mcp/solution/compiler/portal_compiler.py +60 -0
  48. package/src/qingflow_mcp/solution/compiler/view_compiler.py +51 -0
  49. package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +173 -0
  50. package/src/qingflow_mcp/solution/design_session.py +222 -0
  51. package/src/qingflow_mcp/solution/design_store.py +100 -0
  52. package/src/qingflow_mcp/solution/executor.py +2339 -0
  53. package/src/qingflow_mcp/solution/normalizer.py +23 -0
  54. package/src/qingflow_mcp/solution/requirements_builder.py +536 -0
  55. package/src/qingflow_mcp/solution/run_store.py +244 -0
  56. package/src/qingflow_mcp/solution/spec_models.py +853 -0
  57. package/src/qingflow_mcp/tools/__init__.py +1 -0
  58. package/src/qingflow_mcp/tools/ai_builder_tools.py +2063 -0
  59. package/src/qingflow_mcp/tools/app_tools.py +850 -0
  60. package/src/qingflow_mcp/tools/approval_tools.py +833 -0
  61. package/src/qingflow_mcp/tools/auth_tools.py +697 -0
  62. package/src/qingflow_mcp/tools/base.py +81 -0
  63. package/src/qingflow_mcp/tools/code_block_tools.py +679 -0
  64. package/src/qingflow_mcp/tools/directory_tools.py +648 -0
  65. package/src/qingflow_mcp/tools/feedback_tools.py +230 -0
  66. package/src/qingflow_mcp/tools/file_tools.py +385 -0
  67. package/src/qingflow_mcp/tools/import_tools.py +1971 -0
  68. package/src/qingflow_mcp/tools/navigation_tools.py +177 -0
  69. package/src/qingflow_mcp/tools/package_tools.py +240 -0
  70. package/src/qingflow_mcp/tools/portal_tools.py +131 -0
  71. package/src/qingflow_mcp/tools/qingbi_report_tools.py +269 -0
  72. package/src/qingflow_mcp/tools/record_tools.py +12739 -0
  73. package/src/qingflow_mcp/tools/role_tools.py +94 -0
  74. package/src/qingflow_mcp/tools/solution_tools.py +3887 -0
  75. package/src/qingflow_mcp/tools/task_context_tools.py +1423 -0
  76. package/src/qingflow_mcp/tools/task_tools.py +843 -0
  77. package/src/qingflow_mcp/tools/view_tools.py +280 -0
  78. package/src/qingflow_mcp/tools/workflow_tools.py +312 -0
  79. package/src/qingflow_mcp/tools/workspace_tools.py +219 -0
@@ -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,184 @@
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, require_list_arg
7
+
8
+
9
+ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
10
+ parser = subparsers.add_parser("builder", help="稳定 builder 命令")
11
+ builder_subparsers = parser.add_subparsers(dest="builder_command", required=True)
12
+
13
+ package = builder_subparsers.add_parser("package", help="应用包")
14
+ package_subparsers = package.add_subparsers(dest="builder_package_command", required=True)
15
+ package_resolve = package_subparsers.add_parser("resolve", help="解析应用包")
16
+ package_resolve.add_argument("--package-name", required=True)
17
+ package_resolve.set_defaults(handler=_handle_package_resolve, format_hint="builder_summary")
18
+
19
+ app = builder_subparsers.add_parser("app", help="应用")
20
+ app_subparsers = app.add_subparsers(dest="builder_app_command", required=True)
21
+
22
+ app_resolve = app_subparsers.add_parser("resolve", help="解析应用")
23
+ app_resolve.add_argument("--app-key", default="")
24
+ app_resolve.add_argument("--app-name", default="")
25
+ app_resolve.add_argument("--package-tag-id", type=int)
26
+ app_resolve.set_defaults(handler=_handle_app_resolve, format_hint="builder_summary")
27
+
28
+ for name, help_text, handler in [
29
+ ("read-summary", "读取应用摘要", _handle_app_read_summary),
30
+ ("read-fields", "读取字段摘要", _handle_app_read_fields),
31
+ ("read-layout", "读取布局摘要", _handle_app_read_layout),
32
+ ("read-views", "读取视图摘要", _handle_app_read_views),
33
+ ("read-flow", "读取流程摘要", _handle_app_read_flow),
34
+ ("read-charts", "读取报表摘要", _handle_app_read_charts),
35
+ ]:
36
+ sub = app_subparsers.add_parser(name, help=help_text)
37
+ sub.add_argument("--app-key", required=True)
38
+ sub.set_defaults(handler=handler, format_hint="builder_summary")
39
+
40
+ portal = builder_subparsers.add_parser("portal", help="门户")
41
+ portal_subparsers = portal.add_subparsers(dest="builder_portal_command", required=True)
42
+ portal_read = portal_subparsers.add_parser("read-summary", help="读取门户摘要")
43
+ portal_read.add_argument("--dash-key", required=True)
44
+ portal_read.add_argument("--being-draft", action=argparse.BooleanOptionalAction, default=True)
45
+ portal_read.set_defaults(handler=_handle_portal_read_summary, format_hint="builder_summary")
46
+
47
+ portal_apply = portal_subparsers.add_parser("apply", help="更新门户")
48
+ portal_apply.add_argument("--dash-key", default="")
49
+ portal_apply.add_argument("--dash-name", default="")
50
+ portal_apply.add_argument("--package-tag-id", type=int)
51
+ portal_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
52
+ portal_apply.add_argument("--sections-file", required=True)
53
+ portal_apply.add_argument("--auth-file")
54
+ portal_apply.add_argument("--icon")
55
+ portal_apply.add_argument("--color")
56
+ portal_apply.add_argument("--hide-copyright", action=argparse.BooleanOptionalAction, default=None)
57
+ portal_apply.add_argument("--dash-global-config-file")
58
+ portal_apply.add_argument("--config-file")
59
+ portal_apply.set_defaults(handler=_handle_portal_apply, format_hint="builder_summary")
60
+
61
+ schema_apply = builder_subparsers.add_parser("schema", help="字段搭建")
62
+ schema_apply_subparsers = schema_apply.add_subparsers(dest="builder_schema_command", required=True)
63
+ schema_apply_apply = schema_apply_subparsers.add_parser("apply", help="执行字段变更")
64
+ schema_apply_apply.add_argument("--app-key", default="")
65
+ schema_apply_apply.add_argument("--package-tag-id", type=int)
66
+ schema_apply_apply.add_argument("--app-name", default="")
67
+ schema_apply_apply.add_argument("--app-title", default="")
68
+ schema_apply_apply.add_argument("--create-if-missing", action="store_true")
69
+ schema_apply_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
70
+ schema_apply_apply.add_argument("--add-fields-file")
71
+ schema_apply_apply.add_argument("--update-fields-file")
72
+ schema_apply_apply.add_argument("--remove-fields-file")
73
+ schema_apply_apply.set_defaults(handler=_handle_schema_apply, format_hint="builder_summary")
74
+
75
+ charts_apply = builder_subparsers.add_parser("charts", help="报表")
76
+ charts_apply_subparsers = charts_apply.add_subparsers(dest="builder_charts_command", required=True)
77
+ charts_apply_apply = charts_apply_subparsers.add_parser("apply", help="执行报表变更")
78
+ charts_apply_apply.add_argument("--app-key", required=True)
79
+ charts_apply_apply.add_argument("--upsert-file")
80
+ charts_apply_apply.add_argument("--remove-chart-ids-file")
81
+ charts_apply_apply.add_argument("--reorder-chart-ids-file")
82
+ charts_apply_apply.set_defaults(handler=_handle_charts_apply, format_hint="builder_summary")
83
+
84
+ publish_verify = builder_subparsers.add_parser("publish", help="发布校验")
85
+ publish_verify_subparsers = publish_verify.add_subparsers(dest="builder_publish_command", required=True)
86
+ publish_verify_verify = publish_verify_subparsers.add_parser("verify", help="校验应用发布")
87
+ publish_verify_verify.add_argument("--app-key", required=True)
88
+ publish_verify_verify.add_argument("--expected-package-tag-id", type=int)
89
+ publish_verify_verify.set_defaults(handler=_handle_publish_verify, format_hint="builder_summary")
90
+
91
+
92
+ def _handle_package_resolve(args: argparse.Namespace, context: CliContext) -> dict:
93
+ return context.builder.package_resolve(profile=args.profile, package_name=args.package_name)
94
+
95
+
96
+ def _handle_app_resolve(args: argparse.Namespace, context: CliContext) -> dict:
97
+ return context.builder.app_resolve(
98
+ profile=args.profile,
99
+ app_key=args.app_key,
100
+ app_name=args.app_name,
101
+ package_tag_id=args.package_tag_id,
102
+ )
103
+
104
+
105
+ def _handle_app_read_summary(args: argparse.Namespace, context: CliContext) -> dict:
106
+ return context.builder.app_read_summary(profile=args.profile, app_key=args.app_key)
107
+
108
+
109
+ def _handle_app_read_fields(args: argparse.Namespace, context: CliContext) -> dict:
110
+ return context.builder.app_read_fields(profile=args.profile, app_key=args.app_key)
111
+
112
+
113
+ def _handle_app_read_layout(args: argparse.Namespace, context: CliContext) -> dict:
114
+ return context.builder.app_read_layout_summary(profile=args.profile, app_key=args.app_key)
115
+
116
+
117
+ def _handle_app_read_views(args: argparse.Namespace, context: CliContext) -> dict:
118
+ return context.builder.app_read_views_summary(profile=args.profile, app_key=args.app_key)
119
+
120
+
121
+ def _handle_app_read_flow(args: argparse.Namespace, context: CliContext) -> dict:
122
+ return context.builder.app_read_flow_summary(profile=args.profile, app_key=args.app_key)
123
+
124
+
125
+ def _handle_app_read_charts(args: argparse.Namespace, context: CliContext) -> dict:
126
+ return context.builder.app_read_charts_summary(profile=args.profile, app_key=args.app_key)
127
+
128
+
129
+ def _handle_portal_read_summary(args: argparse.Namespace, context: CliContext) -> dict:
130
+ return context.builder.portal_read_summary(
131
+ profile=args.profile,
132
+ dash_key=args.dash_key,
133
+ being_draft=bool(args.being_draft),
134
+ )
135
+
136
+
137
+ def _handle_schema_apply(args: argparse.Namespace, context: CliContext) -> dict:
138
+ return context.builder.app_schema_apply(
139
+ profile=args.profile,
140
+ app_key=args.app_key,
141
+ package_tag_id=args.package_tag_id,
142
+ app_name=args.app_name,
143
+ app_title=args.app_title,
144
+ create_if_missing=bool(args.create_if_missing),
145
+ publish=bool(args.publish),
146
+ add_fields=load_list_arg(args.add_fields_file, option_name="--add-fields-file"),
147
+ update_fields=load_list_arg(args.update_fields_file, option_name="--update-fields-file"),
148
+ remove_fields=load_list_arg(args.remove_fields_file, option_name="--remove-fields-file"),
149
+ )
150
+
151
+
152
+ def _handle_charts_apply(args: argparse.Namespace, context: CliContext) -> dict:
153
+ return context.builder.app_charts_apply(
154
+ profile=args.profile,
155
+ app_key=args.app_key,
156
+ upsert_charts=load_list_arg(args.upsert_file, option_name="--upsert-file"),
157
+ remove_chart_ids=load_list_arg(args.remove_chart_ids_file, option_name="--remove-chart-ids-file"),
158
+ reorder_chart_ids=load_list_arg(args.reorder_chart_ids_file, option_name="--reorder-chart-ids-file"),
159
+ )
160
+
161
+
162
+ def _handle_portal_apply(args: argparse.Namespace, context: CliContext) -> dict:
163
+ return context.builder.portal_apply(
164
+ profile=args.profile,
165
+ dash_key=args.dash_key,
166
+ dash_name=args.dash_name,
167
+ package_tag_id=args.package_tag_id,
168
+ publish=bool(args.publish),
169
+ sections=require_list_arg(args.sections_file, option_name="--sections-file"),
170
+ auth=load_object_arg(args.auth_file, option_name="--auth-file"),
171
+ icon=args.icon,
172
+ color=args.color,
173
+ hide_copyright=args.hide_copyright,
174
+ dash_global_config=load_object_arg(args.dash_global_config_file, option_name="--dash-global-config-file"),
175
+ config=load_object_arg(args.config_file, option_name="--config-file"),
176
+ )
177
+
178
+
179
+ def _handle_publish_verify(args: argparse.Namespace, context: CliContext) -> dict:
180
+ return context.builder.app_publish_verify(
181
+ profile=args.profile,
182
+ app_key=args.app_key,
183
+ expected_package_tag_id=args.expected_package_tag_id,
184
+ )
@@ -0,0 +1,47 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import sys
5
+ from typing import Any
6
+
7
+ from ...errors import QingflowApiError
8
+ from ..json_io import load_json_list, load_json_object, load_optional_json_list, load_optional_json_object
9
+
10
+
11
+ def parse_bool_text(value: str) -> bool:
12
+ normalized = value.strip().lower()
13
+ if normalized in {"true", "1", "yes", "y", "on"}:
14
+ return True
15
+ if normalized in {"false", "0", "no", "n", "off"}:
16
+ return False
17
+ raise argparse.ArgumentTypeError("expected one of: true, false, 1, 0, yes, no")
18
+
19
+
20
+ def load_list_arg(path: str | None, *, option_name: str) -> list[Any]:
21
+ return load_optional_json_list(path, option_name=option_name)
22
+
23
+
24
+ def load_object_arg(path: str | None, *, option_name: str) -> dict[str, Any] | None:
25
+ return load_optional_json_object(path, option_name=option_name)
26
+
27
+
28
+ def require_list_arg(path: str | None, *, option_name: str) -> list[Any]:
29
+ if not path:
30
+ raise QingflowApiError.config_error(f"{option_name} is required")
31
+ return load_json_list(path, option_name=option_name)
32
+
33
+
34
+ def require_object_arg(path: str | None, *, option_name: str) -> dict[str, Any]:
35
+ if not path:
36
+ raise QingflowApiError.config_error(f"{option_name} is required")
37
+ return load_json_object(path, option_name=option_name)
38
+
39
+
40
+ def read_secret_arg(value: str | None, *, stdin_enabled: bool, label: str) -> str:
41
+ if stdin_enabled:
42
+ secret = sys.stdin.read().strip()
43
+ if secret:
44
+ return secret
45
+ if value:
46
+ return value
47
+ raise QingflowApiError.config_error(f"{label} is required")
@@ -0,0 +1,86 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+
5
+ from ..context import CliContext
6
+ from .common import parse_bool_text
7
+
8
+
9
+ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
10
+ parser = subparsers.add_parser("import", help="导入")
11
+ import_subparsers = parser.add_subparsers(dest="import_command", required=True)
12
+
13
+ template = import_subparsers.add_parser("template", help="下载导入模板")
14
+ template.add_argument("--app-key", required=True)
15
+ template.add_argument("--download-to-path")
16
+ template.set_defaults(handler=_handle_template, format_hint="")
17
+
18
+ verify = import_subparsers.add_parser("verify", help="校验导入文件")
19
+ verify.add_argument("--app-key", required=True)
20
+ verify.add_argument("--file-path", required=True)
21
+ verify.set_defaults(handler=_handle_verify, format_hint="import_verify")
22
+
23
+ repair = import_subparsers.add_parser("repair", help="授权后修复导入文件")
24
+ repair.add_argument("--verification-id", required=True)
25
+ repair.add_argument("--authorized-file-modification", action="store_true")
26
+ repair.add_argument("--output-path")
27
+ repair.add_argument("--repair", dest="selected_repairs", action="append", default=[])
28
+ repair.set_defaults(handler=_handle_repair, format_hint="")
29
+
30
+ start = import_subparsers.add_parser("start", help="启动导入")
31
+ start.add_argument("--app-key", required=True)
32
+ start.add_argument("--verification-id", required=True)
33
+ start.add_argument("--being-enter-auditing", type=parse_bool_text, required=True)
34
+ start.add_argument("--view-key")
35
+ start.set_defaults(handler=_handle_start, format_hint="")
36
+
37
+ status = import_subparsers.add_parser("status", help="查询导入状态")
38
+ status.add_argument("--app-key", required=True)
39
+ status.add_argument("--import-id")
40
+ status.add_argument("--process-id-str")
41
+ status.set_defaults(handler=_handle_status, format_hint="import_status")
42
+
43
+
44
+ def _handle_template(args: argparse.Namespace, context: CliContext) -> dict:
45
+ return context.imports.record_import_template_get(
46
+ profile=args.profile,
47
+ app_key=args.app_key,
48
+ download_to_path=args.download_to_path,
49
+ )
50
+
51
+
52
+ def _handle_verify(args: argparse.Namespace, context: CliContext) -> dict:
53
+ return context.imports.record_import_verify(
54
+ profile=args.profile,
55
+ app_key=args.app_key,
56
+ file_path=args.file_path,
57
+ )
58
+
59
+
60
+ def _handle_repair(args: argparse.Namespace, context: CliContext) -> dict:
61
+ return context.imports.record_import_repair_local(
62
+ profile=args.profile,
63
+ verification_id=args.verification_id,
64
+ authorized_file_modification=bool(args.authorized_file_modification),
65
+ output_path=args.output_path,
66
+ selected_repairs=list(args.selected_repairs or []),
67
+ )
68
+
69
+
70
+ def _handle_start(args: argparse.Namespace, context: CliContext) -> dict:
71
+ return context.imports.record_import_start(
72
+ profile=args.profile,
73
+ app_key=args.app_key,
74
+ verification_id=args.verification_id,
75
+ being_enter_auditing=bool(args.being_enter_auditing),
76
+ view_key=args.view_key,
77
+ )
78
+
79
+
80
+ def _handle_status(args: argparse.Namespace, context: CliContext) -> dict:
81
+ return context.imports.record_import_status_get(
82
+ profile=args.profile,
83
+ app_key=args.app_key,
84
+ import_id=args.import_id,
85
+ process_id_str=args.process_id_str,
86
+ )
@@ -0,0 +1,202 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from typing import Any
5
+
6
+ from ...errors import QingflowApiError
7
+ from ..context import CliContext
8
+ from .common import load_list_arg, load_object_arg, require_list_arg, require_object_arg
9
+
10
+
11
+ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
12
+ parser = subparsers.add_parser("record", help="记录与表结构")
13
+ record_subparsers = parser.add_subparsers(dest="record_command", required=True)
14
+
15
+ schema = record_subparsers.add_parser("schema", help="读取记录相关表结构")
16
+ schema.add_argument("--app-key", required=True)
17
+ schema.add_argument("--mode", choices=["applicant", "browse", "insert", "update", "import", "code-block"], default="applicant")
18
+ schema.add_argument("--view-id")
19
+ schema.add_argument("--record-id", type=int)
20
+ schema.set_defaults(handler=_handle_schema, format_hint="")
21
+
22
+ list_parser = record_subparsers.add_parser("list", help="列出记录")
23
+ list_parser.add_argument("--app-key", required=True)
24
+ list_parser.add_argument("--column", dest="columns", action="append", type=int, default=[])
25
+ list_parser.add_argument("--columns-file")
26
+ list_parser.add_argument("--where-file")
27
+ list_parser.add_argument("--order-by-file")
28
+ list_parser.add_argument("--limit", type=int, default=20)
29
+ list_parser.add_argument("--page", type=int, default=1)
30
+ list_parser.add_argument("--view-id")
31
+ list_parser.set_defaults(handler=_handle_list, format_hint="record_list")
32
+
33
+ get = record_subparsers.add_parser("get", help="读取单条记录")
34
+ get.add_argument("--app-key", required=True)
35
+ get.add_argument("--record-id", required=True, type=int)
36
+ get.add_argument("--column", dest="columns", action="append", type=int, default=[])
37
+ get.add_argument("--columns-file")
38
+ get.add_argument("--view-id")
39
+ get.set_defaults(handler=_handle_get, format_hint="")
40
+
41
+ insert = record_subparsers.add_parser("insert", help="新增记录")
42
+ insert.add_argument("--app-key", required=True)
43
+ insert.add_argument("--fields-file", required=True)
44
+ insert.add_argument("--verify-write", action=argparse.BooleanOptionalAction, default=True)
45
+ insert.set_defaults(handler=_handle_insert, format_hint="")
46
+
47
+ update = record_subparsers.add_parser("update", help="更新记录")
48
+ update.add_argument("--app-key", required=True)
49
+ update.add_argument("--record-id", required=True, type=int)
50
+ update.add_argument("--fields-file", required=True)
51
+ update.add_argument("--verify-write", action=argparse.BooleanOptionalAction, default=True)
52
+ update.set_defaults(handler=_handle_update, format_hint="")
53
+
54
+ delete = record_subparsers.add_parser("delete", help="删除记录")
55
+ delete.add_argument("--app-key", required=True)
56
+ delete.add_argument("--record-id", type=int)
57
+ delete.add_argument("--record-ids-file")
58
+ delete.set_defaults(handler=_handle_delete, format_hint="")
59
+
60
+ analyze = record_subparsers.add_parser("analyze", help="分析记录数据")
61
+ analyze.add_argument("--app-key", required=True)
62
+ analyze.add_argument("--dimensions-file")
63
+ analyze.add_argument("--metrics-file")
64
+ analyze.add_argument("--filters-file")
65
+ analyze.add_argument("--sort-file")
66
+ analyze.add_argument("--limit", type=int, default=20)
67
+ analyze.add_argument("--strict-full", action=argparse.BooleanOptionalAction, default=False)
68
+ analyze.add_argument("--view-id")
69
+ analyze.set_defaults(handler=_handle_analyze, format_hint="")
70
+
71
+ code_block = record_subparsers.add_parser("code-block-run", help="执行代码块字段")
72
+ code_block.add_argument("--app-key", required=True)
73
+ code_block.add_argument("--record-id", required=True, type=int)
74
+ code_block.add_argument("--code-block-field", required=True)
75
+ code_block.add_argument("--role", type=int, default=1)
76
+ code_block.add_argument("--workflow-node-id", type=int)
77
+ code_block.add_argument("--answers-file")
78
+ code_block.add_argument("--fields-file")
79
+ code_block.add_argument("--manual", action=argparse.BooleanOptionalAction, default=True)
80
+ code_block.add_argument("--verify-writeback", action=argparse.BooleanOptionalAction, default=True)
81
+ code_block.add_argument("--force-refresh-form", action="store_true")
82
+ code_block.set_defaults(handler=_handle_code_block_run, format_hint="")
83
+
84
+
85
+ def _columns(args: argparse.Namespace) -> list[Any]:
86
+ columns: list[Any] = list(args.columns or [])
87
+ if args.columns_file:
88
+ columns.extend(require_list_arg(args.columns_file, option_name="--columns-file"))
89
+ return columns
90
+
91
+
92
+ def _handle_schema(args: argparse.Namespace, context: CliContext) -> dict:
93
+ mode = args.mode
94
+ if mode == "applicant":
95
+ return context.record.record_schema_get(
96
+ profile=args.profile,
97
+ app_key=args.app_key,
98
+ schema_mode="applicant",
99
+ )
100
+ if mode == "browse":
101
+ if not args.view_id:
102
+ raise QingflowApiError.config_error("--view-id is required when --mode browse")
103
+ return context.record.record_browse_schema_get_public(
104
+ profile=args.profile,
105
+ app_key=args.app_key,
106
+ view_id=args.view_id,
107
+ )
108
+ if mode == "insert":
109
+ return context.record.record_insert_schema_get_public(profile=args.profile, app_key=args.app_key)
110
+ if mode == "update":
111
+ if not args.record_id:
112
+ raise QingflowApiError.config_error("--record-id is required when --mode update")
113
+ return context.record.record_update_schema_get_public(
114
+ profile=args.profile,
115
+ app_key=args.app_key,
116
+ record_id=args.record_id,
117
+ )
118
+ if mode == "import":
119
+ return context.imports.record_import_schema_get(profile=args.profile, app_key=args.app_key)
120
+ return context.code_block.record_code_block_schema_get_public(profile=args.profile, app_key=args.app_key)
121
+
122
+
123
+ def _handle_list(args: argparse.Namespace, context: CliContext) -> dict:
124
+ return context.record.record_list(
125
+ profile=args.profile,
126
+ app_key=args.app_key,
127
+ columns=_columns(args),
128
+ where=load_list_arg(args.where_file, option_name="--where-file"),
129
+ order_by=load_list_arg(args.order_by_file, option_name="--order-by-file"),
130
+ limit=args.limit,
131
+ page=args.page,
132
+ view_id=args.view_id,
133
+ )
134
+
135
+
136
+ def _handle_get(args: argparse.Namespace, context: CliContext) -> dict:
137
+ return context.record.record_get_public(
138
+ profile=args.profile,
139
+ app_key=args.app_key,
140
+ record_id=args.record_id,
141
+ columns=_columns(args),
142
+ view_id=args.view_id,
143
+ )
144
+
145
+
146
+ def _handle_insert(args: argparse.Namespace, context: CliContext) -> dict:
147
+ return context.record.record_insert_public(
148
+ profile=args.profile,
149
+ app_key=args.app_key,
150
+ fields=require_object_arg(args.fields_file, option_name="--fields-file"),
151
+ verify_write=bool(args.verify_write),
152
+ )
153
+
154
+
155
+ def _handle_update(args: argparse.Namespace, context: CliContext) -> dict:
156
+ return context.record.record_update_public(
157
+ profile=args.profile,
158
+ app_key=args.app_key,
159
+ record_id=args.record_id,
160
+ fields=require_object_arg(args.fields_file, option_name="--fields-file"),
161
+ verify_write=bool(args.verify_write),
162
+ )
163
+
164
+
165
+ def _handle_delete(args: argparse.Namespace, context: CliContext) -> dict:
166
+ record_ids = load_list_arg(args.record_ids_file, option_name="--record-ids-file")
167
+ return context.record.record_delete_public(
168
+ profile=args.profile,
169
+ app_key=args.app_key,
170
+ record_id=args.record_id,
171
+ record_ids=record_ids,
172
+ )
173
+
174
+
175
+ def _handle_analyze(args: argparse.Namespace, context: CliContext) -> dict:
176
+ return context.record.record_analyze(
177
+ profile=args.profile,
178
+ app_key=args.app_key,
179
+ dimensions=load_list_arg(args.dimensions_file, option_name="--dimensions-file"),
180
+ metrics=load_list_arg(args.metrics_file, option_name="--metrics-file"),
181
+ filters=load_list_arg(args.filters_file, option_name="--filters-file"),
182
+ sort=load_list_arg(args.sort_file, option_name="--sort-file"),
183
+ limit=args.limit,
184
+ strict_full=bool(args.strict_full),
185
+ view_id=args.view_id,
186
+ )
187
+
188
+
189
+ def _handle_code_block_run(args: argparse.Namespace, context: CliContext) -> dict:
190
+ return context.code_block.record_code_block_run(
191
+ profile=args.profile,
192
+ app_key=args.app_key,
193
+ record_id=args.record_id,
194
+ code_block_field=args.code_block_field,
195
+ role=args.role,
196
+ workflow_node_id=args.workflow_node_id,
197
+ answers=load_list_arg(args.answers_file, option_name="--answers-file"),
198
+ fields=load_object_arg(args.fields_file, option_name="--fields-file") or {},
199
+ manual=bool(args.manual),
200
+ verify_writeback=bool(args.verify_writeback),
201
+ force_refresh_form=bool(args.force_refresh_form),
202
+ )