@qingflow-tech/qingflow-app-builder-mcp 1.0.3 → 1.0.5

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 (36) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/pyproject.toml +2 -1
  4. package/src/qingflow_mcp/__init__.py +1 -1
  5. package/src/qingflow_mcp/backend_client.py +164 -1
  6. package/src/qingflow_mcp/builder_facade/button_style_catalog.py +282 -0
  7. package/src/qingflow_mcp/builder_facade/models.py +44 -5
  8. package/src/qingflow_mcp/builder_facade/service.py +21 -8
  9. package/src/qingflow_mcp/cli/commands/__init__.py +2 -1
  10. package/src/qingflow_mcp/cli/commands/app.py +47 -1
  11. package/src/qingflow_mcp/cli/commands/builder.py +7 -0
  12. package/src/qingflow_mcp/cli/commands/exports.py +111 -0
  13. package/src/qingflow_mcp/cli/commands/record.py +44 -5
  14. package/src/qingflow_mcp/cli/commands/task.py +644 -22
  15. package/src/qingflow_mcp/cli/commands/workspace.py +64 -2
  16. package/src/qingflow_mcp/cli/context.py +3 -0
  17. package/src/qingflow_mcp/cli/formatters.py +240 -5
  18. package/src/qingflow_mcp/cli/interaction.py +72 -0
  19. package/src/qingflow_mcp/cli/main.py +5 -0
  20. package/src/qingflow_mcp/cli/terminal_ui.py +218 -0
  21. package/src/qingflow_mcp/errors.py +2 -2
  22. package/src/qingflow_mcp/export_store.py +14 -0
  23. package/src/qingflow_mcp/public_surface.py +7 -1
  24. package/src/qingflow_mcp/response_trim.py +188 -10
  25. package/src/qingflow_mcp/server.py +37 -9
  26. package/src/qingflow_mcp/server_app_builder.py +4 -0
  27. package/src/qingflow_mcp/server_app_user.py +115 -10
  28. package/src/qingflow_mcp/session_store.py +57 -6
  29. package/src/qingflow_mcp/tools/ai_builder_tools.py +59 -16
  30. package/src/qingflow_mcp/tools/auth_tools.py +26 -0
  31. package/src/qingflow_mcp/tools/custom_button_tools.py +0 -2
  32. package/src/qingflow_mcp/tools/export_tools.py +1565 -0
  33. package/src/qingflow_mcp/tools/import_tools.py +42 -2
  34. package/src/qingflow_mcp/tools/record_tools.py +12793 -8612
  35. package/src/qingflow_mcp/tools/resource_read_tools.py +40 -1
  36. package/src/qingflow_mcp/tools/task_context_tools.py +26 -8
@@ -34,6 +34,7 @@ from ..tools.role_tools import RoleTools
34
34
  from ..tools.solution_tools import SolutionTools
35
35
  from ..tools.view_tools import ViewTools
36
36
  from ..tools.workflow_tools import WorkflowTools
37
+ from .button_style_catalog import button_style_catalog_payload
37
38
  from .models import (
38
39
  AppChartsReadResponse,
39
40
  AppFieldsReadResponse,
@@ -2353,6 +2354,26 @@ class AiBuilderFacade:
2353
2354
  **match,
2354
2355
  }
2355
2356
 
2357
+ def button_style_catalog_get(self, *, profile: str) -> JSONObject:
2358
+ return {
2359
+ "status": "success",
2360
+ "error_code": None,
2361
+ "recoverable": False,
2362
+ "message": "read button style catalog",
2363
+ "normalized_args": {},
2364
+ "missing_fields": [],
2365
+ "allowed_values": {},
2366
+ "details": {},
2367
+ "request_id": None,
2368
+ "suggested_next_call": None,
2369
+ "noop": False,
2370
+ "warnings": [],
2371
+ "verification": {"button_style_catalog_verified": True},
2372
+ "verified": True,
2373
+ "profile": profile,
2374
+ **button_style_catalog_payload(),
2375
+ }
2376
+
2356
2377
  def app_custom_button_list(self, *, profile: str, app_key: str) -> JSONObject:
2357
2378
  normalized_args = {"app_key": app_key}
2358
2379
  permission_outcomes: list[PermissionCheckOutcome] = []
@@ -8035,8 +8056,6 @@ def _serialize_custom_button_payload(payload: CustomButtonPatch) -> dict[str, An
8035
8056
  "buttonIcon": data["button_icon"],
8036
8057
  "triggerAction": data["trigger_action"],
8037
8058
  }
8038
- if str(data.get("icon_color") or "").strip():
8039
- serialized["iconColor"] = data["icon_color"]
8040
8059
  if str(data.get("trigger_link_url") or "").strip():
8041
8060
  serialized["triggerLinkUrl"] = data["trigger_link_url"]
8042
8061
  trigger_add_data_config = data.get("trigger_add_data_config")
@@ -8126,7 +8145,6 @@ def _normalize_custom_button_summary(item: dict[str, Any]) -> dict[str, Any]:
8126
8145
  "button_id": _coerce_positive_int(item.get("button_id") or item.get("buttonId") or item.get("id")),
8127
8146
  "button_text": str(item.get("button_text") or item.get("buttonText") or "").strip() or None,
8128
8147
  "button_icon": str(item.get("button_icon") or item.get("buttonIcon") or "").strip() or None,
8129
- "icon_color": str(item.get("icon_color") or item.get("iconColor") or "").strip() or None,
8130
8148
  "background_color": str(item.get("background_color") or item.get("backgroundColor") or "").strip() or None,
8131
8149
  "text_color": str(item.get("text_color") or item.get("textColor") or "").strip() or None,
8132
8150
  "used_in_chart_count": _coerce_nonnegative_int(item.get("used_in_chart_count") or item.get("userInChartCount")),
@@ -14887,7 +14905,6 @@ def _normalize_view_button_entry(entry: dict[str, Any]) -> dict[str, Any]:
14887
14905
  for public_key, source_key in (
14888
14906
  ("default_button_text", "defaultButtonText"),
14889
14907
  ("button_icon", "buttonIcon"),
14890
- ("icon_color", "iconColor"),
14891
14908
  ("background_color", "backgroundColor"),
14892
14909
  ("text_color", "textColor"),
14893
14910
  ("trigger_link_url", "triggerLinkUrl"),
@@ -14925,7 +14942,6 @@ def _normalize_view_buttons_for_compare(value: Any) -> list[dict[str, Any]]:
14925
14942
  "button_id": normalized.get("button_id") if is_custom else None,
14926
14943
  "button_text": normalized.get("button_text"),
14927
14944
  "button_icon": normalized.get("button_icon"),
14928
- "icon_color": normalized.get("icon_color"),
14929
14945
  "background_color": normalized.get("background_color"),
14930
14946
  "text_color": normalized.get("text_color"),
14931
14947
  "trigger_action": normalized.get("trigger_action"),
@@ -15000,7 +15016,6 @@ def _normalize_expected_view_buttons_for_compare(
15000
15016
  for key in (
15001
15017
  "button_text",
15002
15018
  "button_icon",
15003
- "icon_color",
15004
15019
  "background_color",
15005
15020
  "text_color",
15006
15021
  "trigger_action",
@@ -15183,8 +15198,6 @@ def _serialize_view_button_binding(
15183
15198
  if binding.button_type in {PublicViewButtonType.system, PublicViewButtonType.custom}:
15184
15199
  dto["buttonText"] = binding.button_text
15185
15200
  dto["buttonIcon"] = binding.button_icon
15186
- if str(binding.icon_color or "").strip():
15187
- dto["iconColor"] = binding.icon_color
15188
15201
  dto["backgroundColor"] = binding.background_color
15189
15202
  dto["textColor"] = binding.text_color
15190
15203
  dto["triggerAction"] = binding.trigger_action
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import argparse
4
4
 
5
- from . import app, auth, builder, chart, imports, portal, record, task, view, workspace
5
+ from . import app, auth, builder, chart, exports, imports, portal, record, task, view, workspace
6
6
 
7
7
 
8
8
  def register_all_commands(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
@@ -14,5 +14,6 @@ def register_all_commands(subparsers: argparse._SubParsersAction[argparse.Argume
14
14
  chart.register(subparsers)
15
15
  record.register(subparsers)
16
16
  imports.register(subparsers)
17
+ exports.register(subparsers)
17
18
  task.register(subparsers)
18
19
  builder.register(subparsers)
@@ -3,6 +3,9 @@ from __future__ import annotations
3
3
  import argparse
4
4
 
5
5
  from ..context import CliContext
6
+ from ..interaction import cancelled_result, resolve_interactive_selection
7
+ from ..terminal_ui import SelectionOption
8
+ from .common import raise_config_error
6
9
 
7
10
 
8
11
  def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
@@ -19,7 +22,7 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
19
22
  search.set_defaults(handler=_handle_search, format_hint="app_search")
20
23
 
21
24
  get = app_subparsers.add_parser("get", help="读取应用可访问视图与导入能力")
22
- get.add_argument("--app-key", required=True)
25
+ get.add_argument("--app-key", help="不传时在交互终端中选择应用")
23
26
  get.set_defaults(handler=_handle_get, format_hint="app_get")
24
27
 
25
28
 
@@ -37,4 +40,47 @@ def _handle_search(args: argparse.Namespace, context: CliContext) -> dict:
37
40
 
38
41
 
39
42
  def _handle_get(args: argparse.Namespace, context: CliContext) -> dict:
43
+ if not (args.app_key or "").strip():
44
+ selection = _choose_app_interactively(args, context)
45
+ if selection.status == "unavailable":
46
+ raise_config_error(
47
+ "app get requires --app-key, or an interactive terminal to choose an app",
48
+ fix_hint="Run `app list` to inspect visible apps, or retry with `--app-key APP_KEY`.",
49
+ )
50
+ if selection.status == "empty":
51
+ raise_config_error(
52
+ selection.message or "app get could not open a selector because no visible apps were returned.",
53
+ fix_hint="Run `app list` to confirm visible apps, or retry with `--app-key APP_KEY`.",
54
+ )
55
+ if selection.status == "cancelled":
56
+ return cancelled_result(selection.message or "已取消")
57
+ args.app_key = str(selection.value or "")
40
58
  return context.app.app_get(profile=args.profile, app_key=args.app_key)
59
+
60
+
61
+ def _choose_app_interactively(args: argparse.Namespace, context: CliContext):
62
+ def load_options() -> list[SelectionOption[str]]:
63
+ result = context.app.app_list(profile=args.profile)
64
+ items = result.get("items") if isinstance(result, dict) and isinstance(result.get("items"), list) else []
65
+ options: list[SelectionOption[str]] = []
66
+ for item in items:
67
+ if not isinstance(item, dict):
68
+ continue
69
+ app_key = str(item.get("app_key") or "").strip()
70
+ if not app_key:
71
+ continue
72
+ app_name = str(item.get("app_name") or app_key).strip() or app_key
73
+ package_name = str(item.get("package_name") or "").strip()
74
+ hint = f"app_key={app_key}"
75
+ if package_name:
76
+ hint += f" · package={package_name}"
77
+ options.append(SelectionOption(value=app_key, label=app_name, hint=hint))
78
+ return options
79
+
80
+ return resolve_interactive_selection(
81
+ args,
82
+ title="选择应用",
83
+ unavailable_message="app get requires --app-key, or an interactive terminal to choose an app",
84
+ empty_message="app get could not open a selector because no visible apps were returned.",
85
+ load_options=load_options,
86
+ )
@@ -120,6 +120,9 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
120
120
  button = builder_subparsers.add_parser("button", help="自定义按钮")
121
121
  button_subparsers = button.add_subparsers(dest="builder_button_command", required=True)
122
122
 
123
+ button_catalog = button_subparsers.add_parser("catalog", help="读取按钮样式目录")
124
+ button_catalog.set_defaults(handler=_handle_button_catalog, format_hint="builder_summary")
125
+
123
126
  button_list = button_subparsers.add_parser("list", help="列出自定义按钮")
124
127
  button_list.add_argument("--app-key", required=True)
125
128
  button_list.set_defaults(handler=_handle_button_list, format_hint="builder_summary")
@@ -362,6 +365,10 @@ def _handle_button_list(args: argparse.Namespace, context: CliContext) -> dict:
362
365
  return context.builder.app_custom_button_list(profile=args.profile, app_key=args.app_key)
363
366
 
364
367
 
368
+ def _handle_button_catalog(args: argparse.Namespace, context: CliContext) -> dict:
369
+ return context.builder.button_style_catalog_get(profile=args.profile)
370
+
371
+
365
372
  def _handle_button_get(args: argparse.Namespace, context: CliContext) -> dict:
366
373
  return context.builder.app_custom_button_get(profile=args.profile, app_key=args.app_key, button_id=args.button_id)
367
374
 
@@ -0,0 +1,111 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+
5
+ from ..context import CliContext
6
+ from .common import load_list_arg
7
+
8
+
9
+ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
10
+ parser = subparsers.add_parser("export", help="导出")
11
+ export_subparsers = parser.add_subparsers(dest="export_command", required=True)
12
+
13
+ start = export_subparsers.add_parser("start", help="启动导出")
14
+ start.add_argument("--app-key", required=True)
15
+ start.add_argument("--view-id", default="system:all")
16
+ start.add_argument("--column", dest="columns", action="append", type=int, default=[], help="只导出这些 field_id;不传时导出当前视图全部字段")
17
+ start.add_argument("--columns-file", help="JSON/YAML list,内容与 --column 语义一致")
18
+ start.add_argument("--where-file", help="JSON/YAML list,内容与 record list 的 where DSL 一致;内部先查命中 record_id 再走原生导出")
19
+ start.add_argument("--order-by-file", help="JSON/YAML list,内容与 record list 的 order_by DSL 一致;内部查询和导出记录顺序保持一致")
20
+ start.add_argument("--record-id", dest="record_ids", action="append", default=[], help="只导出这些 record_id;不传时导出当前视图全部数据")
21
+ start.add_argument("--record-ids-file", help="JSON/YAML list,内容与 --record-id 语义一致")
22
+ start.add_argument("--include-workflow-log", action=argparse.BooleanOptionalAction, default=False, help="是否同时导出流程日志")
23
+ start.set_defaults(handler=_handle_start, format_hint="export_start")
24
+
25
+ status = export_subparsers.add_parser("status", help="查询导出状态")
26
+ status.add_argument("--export-handle", required=True)
27
+ status.set_defaults(handler=_handle_status, format_hint="export_status")
28
+
29
+ get = export_subparsers.add_parser("get", help="获取导出结果")
30
+ get.add_argument("--export-handle", required=True)
31
+ get.add_argument("--download-to-path")
32
+ get.set_defaults(handler=_handle_get, format_hint="export_get")
33
+
34
+ direct = export_subparsers.add_parser("direct", help="直接导出并下载")
35
+ direct.add_argument("--app-key", required=True)
36
+ direct.add_argument("--view-id", default="system:all")
37
+ direct.add_argument("--column", dest="columns", action="append", type=int, default=[], help="只导出这些 field_id;不传时导出当前视图全部字段")
38
+ direct.add_argument("--columns-file", help="JSON/YAML list,内容与 --column 语义一致")
39
+ direct.add_argument("--where-file", help="JSON/YAML list,内容与 record list 的 where DSL 一致;内部先查命中 record_id 再走原生导出")
40
+ direct.add_argument("--order-by-file", help="JSON/YAML list,内容与 record list 的 order_by DSL 一致;内部查询和导出记录顺序保持一致")
41
+ direct.add_argument("--record-id", dest="record_ids", action="append", default=[], help="只导出这些 record_id;不传时导出当前视图全部数据")
42
+ direct.add_argument("--record-ids-file", help="JSON/YAML list,内容与 --record-id 语义一致")
43
+ direct.add_argument("--include-workflow-log", action=argparse.BooleanOptionalAction, default=False, help="是否同时导出流程日志")
44
+ direct.add_argument("--download-to-path")
45
+ direct.add_argument("--wait-timeout-seconds", type=float)
46
+ direct.set_defaults(handler=_handle_direct, format_hint="export_direct")
47
+
48
+
49
+ def _columns(args: argparse.Namespace) -> list[int | dict]:
50
+ columns: list[int | dict] = list(args.columns or [])
51
+ if args.columns_file:
52
+ columns.extend(load_list_arg(args.columns_file, option_name="--columns-file"))
53
+ return columns
54
+
55
+
56
+ def _record_ids(args: argparse.Namespace) -> list[str | int]:
57
+ record_ids: list[str | int] = list(args.record_ids or [])
58
+ if args.record_ids_file:
59
+ record_ids.extend(load_list_arg(args.record_ids_file, option_name="--record-ids-file"))
60
+ return record_ids
61
+
62
+
63
+ def _where(args: argparse.Namespace) -> list[dict]:
64
+ return load_list_arg(args.where_file, option_name="--where-file") if args.where_file else []
65
+
66
+
67
+ def _order_by(args: argparse.Namespace) -> list[dict]:
68
+ return load_list_arg(args.order_by_file, option_name="--order-by-file") if args.order_by_file else []
69
+
70
+
71
+ def _handle_start(args: argparse.Namespace, context: CliContext) -> dict:
72
+ return context.exports.record_export_start(
73
+ profile=args.profile,
74
+ app_key=args.app_key,
75
+ view_id=args.view_id,
76
+ columns=_columns(args),
77
+ where=_where(args),
78
+ order_by=_order_by(args),
79
+ record_ids=_record_ids(args),
80
+ include_workflow_log=args.include_workflow_log,
81
+ )
82
+
83
+
84
+ def _handle_status(args: argparse.Namespace, context: CliContext) -> dict:
85
+ return context.exports.record_export_status_get(
86
+ profile=args.profile,
87
+ export_handle=args.export_handle,
88
+ )
89
+
90
+
91
+ def _handle_get(args: argparse.Namespace, context: CliContext) -> dict:
92
+ return context.exports.record_export_get(
93
+ profile=args.profile,
94
+ export_handle=args.export_handle,
95
+ download_to_path=args.download_to_path,
96
+ )
97
+
98
+
99
+ def _handle_direct(args: argparse.Namespace, context: CliContext) -> dict:
100
+ return context.exports.record_export_direct(
101
+ profile=args.profile,
102
+ app_key=args.app_key,
103
+ view_id=args.view_id,
104
+ columns=_columns(args),
105
+ where=_where(args),
106
+ order_by=_order_by(args),
107
+ record_ids=_record_ids(args),
108
+ include_workflow_log=args.include_workflow_log,
109
+ download_to_path=args.download_to_path,
110
+ wait_timeout_seconds=args.wait_timeout_seconds,
111
+ )
@@ -10,7 +10,11 @@ from .common import load_list_arg, load_object_arg, raise_config_error, require_
10
10
 
11
11
  def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
12
12
  parser = subparsers.add_parser("record", help="记录与表结构")
13
- record_subparsers = parser.add_subparsers(dest="record_command", required=True)
13
+ record_subparsers = parser.add_subparsers(
14
+ dest="record_command",
15
+ required=True,
16
+ metavar="{schema,list,access,get,insert,update,delete,code-block-run}",
17
+ )
14
18
 
15
19
  schema = record_subparsers.add_parser("schema", help="读取记录相关表结构")
16
20
  schema.add_argument("--mode", dest="legacy_mode", help=argparse.SUPPRESS)
@@ -47,9 +51,11 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
47
51
  list_parser.add_argument("--app-key", required=True)
48
52
  list_parser.add_argument("--column", dest="columns", action="append", type=int, default=[])
49
53
  list_parser.add_argument("--columns-file")
54
+ list_parser.add_argument("--query")
55
+ list_parser.add_argument("--query-field", dest="query_fields", action="append", type=int, default=[])
56
+ list_parser.add_argument("--query-fields-file")
50
57
  list_parser.add_argument("--where-file")
51
58
  list_parser.add_argument("--order-by-file")
52
- list_parser.add_argument("--limit", type=int, default=20)
53
59
  list_parser.add_argument("--page", type=int, default=1)
54
60
  list_parser.add_argument("--view-id")
55
61
  list_parser.add_argument("--list-type", dest="legacy_list_type", type=int, help=argparse.SUPPRESS)
@@ -57,13 +63,22 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
57
63
  list_parser.add_argument("--view-name", dest="legacy_view_name", help=argparse.SUPPRESS)
58
64
  list_parser.set_defaults(handler=_handle_list, format_hint="record_list")
59
65
 
66
+ access_parser = record_subparsers.add_parser("access", help="访问记录并写入本地 CSV 分片")
67
+ access_parser.add_argument("--app-key", required=True)
68
+ access_parser.add_argument("--column", dest="columns", action="append", type=int, default=[])
69
+ access_parser.add_argument("--columns-file")
70
+ access_parser.add_argument("--where-file")
71
+ access_parser.add_argument("--order-by-file")
72
+ access_parser.add_argument("--view-id", required=True)
73
+ access_parser.set_defaults(handler=_handle_access, format_hint="record_access")
74
+
60
75
  get = record_subparsers.add_parser("get", help="读取单条记录")
61
76
  get.add_argument("--app-key", required=True)
62
77
  get.add_argument("--record-id", required=True)
63
78
  get.add_argument("--column", dest="columns", action="append", type=int, default=[])
64
79
  get.add_argument("--columns-file")
65
80
  get.add_argument("--view-id")
66
- get.set_defaults(handler=_handle_get, format_hint="")
81
+ get.set_defaults(handler=_handle_get, format_hint="record_get")
67
82
 
68
83
  insert = record_subparsers.add_parser("insert", help="新增记录")
69
84
  insert.add_argument("--app-key", required=True)
@@ -86,7 +101,12 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
86
101
  delete.add_argument("--record-ids-file")
87
102
  delete.set_defaults(handler=_handle_delete, format_hint="")
88
103
 
89
- analyze = record_subparsers.add_parser("analyze", help="分析记录数据")
104
+ analyze = record_subparsers.add_parser("analyze", help=argparse.SUPPRESS)
105
+ record_subparsers._choices_actions = [ # type: ignore[attr-defined]
106
+ action
107
+ for action in record_subparsers._choices_actions # type: ignore[attr-defined]
108
+ if getattr(action, "dest", None) != "analyze"
109
+ ]
90
110
  analyze.add_argument("--app-key", required=True)
91
111
  analyze.add_argument("--dimensions-file")
92
112
  analyze.add_argument("--metrics-file")
@@ -122,6 +142,13 @@ def _columns(args: argparse.Namespace) -> list[Any]:
122
142
  return columns
123
143
 
124
144
 
145
+ def _query_fields(args: argparse.Namespace) -> list[Any]:
146
+ query_fields: list[Any] = list(getattr(args, "query_fields", None) or [])
147
+ if getattr(args, "query_fields_file", None):
148
+ query_fields.extend(require_list_arg(args.query_fields_file, option_name="--query-fields-file"))
149
+ return query_fields
150
+
151
+
125
152
  def _handle_schema_root(args: argparse.Namespace, _context: CliContext) -> dict:
126
153
  mode = (args.legacy_mode or "").strip()
127
154
  if mode:
@@ -216,14 +243,26 @@ def _handle_list(args: argparse.Namespace, context: CliContext) -> dict:
216
243
  profile=args.profile,
217
244
  app_key=args.app_key,
218
245
  columns=_columns(args),
246
+ query=args.query,
247
+ query_fields=_query_fields(args),
219
248
  where=load_list_arg(args.where_file, option_name="--where-file"),
220
249
  order_by=load_list_arg(args.order_by_file, option_name="--order-by-file"),
221
- limit=args.limit,
222
250
  page=args.page,
223
251
  view_id=args.view_id,
224
252
  )
225
253
 
226
254
 
255
+ def _handle_access(args: argparse.Namespace, context: CliContext) -> dict:
256
+ return context.record.record_access(
257
+ profile=args.profile,
258
+ app_key=args.app_key,
259
+ columns=_columns(args),
260
+ where=load_list_arg(args.where_file, option_name="--where-file"),
261
+ order_by=load_list_arg(args.order_by_file, option_name="--order-by-file"),
262
+ view_id=args.view_id,
263
+ )
264
+
265
+
227
266
  def _handle_get(args: argparse.Namespace, context: CliContext) -> dict:
228
267
  return context.record.record_get_public(
229
268
  profile=args.profile,