@qingflow-tech/qingflow-app-user-mcp 1.0.10 → 1.0.12

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 (89) hide show
  1. package/README.md +9 -3
  2. package/docs/local-agent-install.md +54 -3
  3. package/entry_point.py +1 -1
  4. package/npm/bin/qingflow-skills.mjs +5 -0
  5. package/npm/lib/runtime.mjs +304 -13
  6. package/npm/scripts/postinstall.mjs +1 -5
  7. package/package.json +3 -2
  8. package/pyproject.toml +1 -1
  9. package/skills/qingflow-app-builder/SKILL.md +255 -0
  10. package/skills/qingflow-app-builder/agents/openai.yaml +4 -0
  11. package/skills/qingflow-app-builder/references/create-app.md +149 -0
  12. package/skills/qingflow-app-builder/references/environments.md +63 -0
  13. package/skills/qingflow-app-builder/references/flow-actors-and-permissions.md +123 -0
  14. package/skills/qingflow-app-builder/references/gotchas.md +107 -0
  15. package/skills/qingflow-app-builder/references/match-rules.md +114 -0
  16. package/skills/qingflow-app-builder/references/public-surface-sync.md +75 -0
  17. package/skills/qingflow-app-builder/references/solution-playbooks.md +52 -0
  18. package/skills/qingflow-app-builder/references/tool-selection.md +99 -0
  19. package/skills/qingflow-app-builder/references/update-flow.md +158 -0
  20. package/skills/qingflow-app-builder/references/update-layout.md +68 -0
  21. package/skills/qingflow-app-builder/references/update-schema.md +72 -0
  22. package/skills/qingflow-app-builder/references/update-views.md +284 -0
  23. package/skills/qingflow-app-builder-code-integrations/SKILL.md +137 -0
  24. package/skills/qingflow-app-builder-code-integrations/agents/openai.yaml +4 -0
  25. package/skills/qingflow-app-builder-code-integrations/references/code-block.md +66 -0
  26. package/skills/qingflow-app-builder-code-integrations/references/q-linker.md +77 -0
  27. package/skills/qingflow-app-user/SKILL.md +12 -11
  28. package/skills/qingflow-app-user/references/data-gotchas.md +2 -2
  29. package/skills/qingflow-app-user/references/public-surface-sync.md +3 -3
  30. package/skills/qingflow-app-user/references/record-patterns.md +5 -5
  31. package/skills/qingflow-app-user/references/workflow-usage.md +4 -5
  32. package/skills/qingflow-mcp-setup/SKILL.md +113 -0
  33. package/skills/qingflow-mcp-setup/agents/openai.yaml +4 -0
  34. package/skills/qingflow-mcp-setup/references/claude-desktop.md +34 -0
  35. package/skills/qingflow-mcp-setup/references/environments.md +62 -0
  36. package/skills/qingflow-mcp-setup/references/generic-stdio.md +32 -0
  37. package/skills/qingflow-mcp-setup/scripts/check_local_server.sh +38 -0
  38. package/skills/qingflow-record-analysis/SKILL.md +6 -7
  39. package/skills/qingflow-record-analysis/manifest.yaml +10 -0
  40. package/skills/qingflow-record-delete/SKILL.md +5 -3
  41. package/skills/qingflow-record-import/SKILL.md +6 -2
  42. package/skills/qingflow-record-insert/SKILL.md +48 -4
  43. package/skills/qingflow-record-insert/manifest.yaml +6 -0
  44. package/skills/qingflow-record-update/SKILL.md +36 -24
  45. package/skills/qingflow-task-ops/SKILL.md +25 -25
  46. package/skills/qingflow-task-ops/references/environments.md +0 -1
  47. package/skills/qingflow-task-ops/references/workflow-usage.md +4 -6
  48. package/src/qingflow_mcp/__main__.py +6 -2
  49. package/src/qingflow_mcp/builder_facade/models.py +41 -2
  50. package/src/qingflow_mcp/builder_facade/service.py +2743 -423
  51. package/src/qingflow_mcp/cli/commands/app.py +3 -16
  52. package/src/qingflow_mcp/cli/commands/builder.py +30 -4
  53. package/src/qingflow_mcp/cli/commands/exports.py +2 -2
  54. package/src/qingflow_mcp/cli/commands/imports.py +1 -1
  55. package/src/qingflow_mcp/cli/commands/record.py +54 -11
  56. package/src/qingflow_mcp/cli/context.py +0 -3
  57. package/src/qingflow_mcp/cli/formatters.py +238 -8
  58. package/src/qingflow_mcp/cli/main.py +47 -3
  59. package/src/qingflow_mcp/errors.py +43 -2
  60. package/src/qingflow_mcp/public_surface.py +24 -16
  61. package/src/qingflow_mcp/response_trim.py +119 -12
  62. package/src/qingflow_mcp/server.py +17 -14
  63. package/src/qingflow_mcp/server_app_builder.py +29 -7
  64. package/src/qingflow_mcp/server_app_user.py +23 -24
  65. package/src/qingflow_mcp/solution/compiler/icon_utils.py +294 -0
  66. package/src/qingflow_mcp/solution/executor.py +112 -15
  67. package/src/qingflow_mcp/tools/ai_builder_tools.py +497 -65
  68. package/src/qingflow_mcp/tools/app_tools.py +237 -51
  69. package/src/qingflow_mcp/tools/approval_tools.py +196 -34
  70. package/src/qingflow_mcp/tools/auth_tools.py +92 -16
  71. package/src/qingflow_mcp/tools/code_block_tools.py +296 -39
  72. package/src/qingflow_mcp/tools/custom_button_tools.py +64 -10
  73. package/src/qingflow_mcp/tools/directory_tools.py +236 -72
  74. package/src/qingflow_mcp/tools/export_tools.py +230 -33
  75. package/src/qingflow_mcp/tools/file_tools.py +7 -3
  76. package/src/qingflow_mcp/tools/import_tools.py +293 -40
  77. package/src/qingflow_mcp/tools/navigation_tools.py +91 -12
  78. package/src/qingflow_mcp/tools/package_tools.py +134 -8
  79. package/src/qingflow_mcp/tools/portal_tools.py +39 -3
  80. package/src/qingflow_mcp/tools/qingbi_report_tools.py +116 -7
  81. package/src/qingflow_mcp/tools/record_tools.py +2305 -442
  82. package/src/qingflow_mcp/tools/resource_read_tools.py +191 -39
  83. package/src/qingflow_mcp/tools/role_tools.py +80 -9
  84. package/src/qingflow_mcp/tools/solution_tools.py +57 -15
  85. package/src/qingflow_mcp/tools/task_context_tools.py +569 -119
  86. package/src/qingflow_mcp/tools/task_tools.py +113 -29
  87. package/src/qingflow_mcp/tools/view_tools.py +106 -3
  88. package/src/qingflow_mcp/tools/workflow_tools.py +17 -1
  89. package/src/qingflow_mcp/tools/workspace_tools.py +71 -3
@@ -13,30 +13,17 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
13
13
  app_subparsers = parser.add_subparsers(dest="app_command", required=True)
14
14
 
15
15
  list_parser = app_subparsers.add_parser("list", help="列出可见应用")
16
+ list_parser.add_argument("--query", default="", help="按关键词在可见应用列表中本地过滤")
17
+ list_parser.add_argument("--keyword", default="", help="兼容别名;建议使用 --query")
16
18
  list_parser.set_defaults(handler=_handle_list, format_hint="app_list")
17
19
 
18
- search = app_subparsers.add_parser("search", help="搜索应用")
19
- search.add_argument("--keyword", default="")
20
- search.add_argument("--page", type=int, default=1)
21
- search.add_argument("--page-size", type=int, default=50)
22
- search.set_defaults(handler=_handle_search, format_hint="app_search")
23
-
24
20
  get = app_subparsers.add_parser("get", help="读取应用可访问视图与导入能力")
25
21
  get.add_argument("--app-key", help="不传时在交互终端中选择应用")
26
22
  get.set_defaults(handler=_handle_get, format_hint="app_get")
27
23
 
28
24
 
29
25
  def _handle_list(args: argparse.Namespace, context: CliContext) -> dict:
30
- return context.app.app_list(profile=args.profile)
31
-
32
-
33
- def _handle_search(args: argparse.Namespace, context: CliContext) -> dict:
34
- return context.app.app_search(
35
- profile=args.profile,
36
- keyword=args.keyword,
37
- page_num=args.page,
38
- page_size=args.page_size,
39
- )
26
+ return context.app.app_list(profile=args.profile, query=args.query, keyword=args.keyword)
40
27
 
41
28
 
42
29
  def _handle_get(args: argparse.Namespace, context: CliContext) -> dict:
@@ -42,10 +42,15 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
42
42
  contract.add_argument("--tool-name", required=True)
43
43
  contract.set_defaults(handler=_handle_contract, format_hint="builder_summary")
44
44
 
45
+ icon = builder_subparsers.add_parser("icon", help="工作区图标目录")
46
+ icon_subparsers = icon.add_subparsers(dest="builder_icon_command", required=True)
47
+ icon_catalog = icon_subparsers.add_parser("catalog", help="读取应用、应用包、门户可用图标目录")
48
+ icon_catalog.set_defaults(handler=_handle_icon_catalog, format_hint="builder_summary")
49
+
45
50
  member = builder_subparsers.add_parser("member", help="成员目录")
46
51
  member_subparsers = member.add_subparsers(dest="builder_member_command", required=True)
47
52
  member_search = member_subparsers.add_parser("search", help="搜索成员")
48
- member_search.add_argument("--query", default="")
53
+ member_search.add_argument("--query", required=True)
49
54
  member_search.add_argument("--page-num", type=int, default=1)
50
55
  member_search.add_argument("--page-size", type=int, default=20)
51
56
  member_search.add_argument("--contain-disable", action=argparse.BooleanOptionalAction, default=False)
@@ -54,7 +59,7 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
54
59
  role = builder_subparsers.add_parser("role", help="角色目录")
55
60
  role_subparsers = role.add_subparsers(dest="builder_role_command", required=True)
56
61
  role_search = role_subparsers.add_parser("search", help="搜索角色")
57
- role_search.add_argument("--keyword", default="")
62
+ role_search.add_argument("--keyword", required=True)
58
63
  role_search.add_argument("--page-num", type=int, default=1)
59
64
  role_search.add_argument("--page-size", type=int, default=20)
60
65
  role_search.set_defaults(handler=_handle_role_search, format_hint="builder_summary")
@@ -78,6 +83,11 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
78
83
  solution_install.add_argument("--solution-source", default="solutionDetail")
79
84
  solution_install.set_defaults(handler=_handle_solution_install, format_hint="builder_summary")
80
85
 
86
+ package_list = package_subparsers.add_parser("list", help="列出应用包")
87
+ package_list.add_argument("--trial-status", default="all")
88
+ package_list.add_argument("--query", default="")
89
+ package_list.set_defaults(handler=_handle_package_list, format_hint="builder_summary")
90
+
81
91
  package_get = package_subparsers.add_parser("get", help="读取应用包详情")
82
92
  package_get.add_argument("--package-id", type=int, required=True)
83
93
  package_get.set_defaults(handler=_handle_package_get, format_hint="builder_summary")
@@ -157,7 +167,9 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
157
167
  portal_apply.add_argument("--dash-name", default="")
158
168
  portal_apply.add_argument("--package-id", type=int)
159
169
  portal_apply.add_argument("--publish", action=argparse.BooleanOptionalAction, default=True)
170
+ portal_apply.add_argument("--payload-file")
160
171
  portal_apply.add_argument("--sections-file")
172
+ portal_apply.add_argument("--layout-preset", default="")
161
173
  portal_apply.add_argument("--visibility-file")
162
174
  portal_apply.add_argument("--auth-file")
163
175
  portal_apply.add_argument("--icon")
@@ -277,6 +289,10 @@ def _handle_contract(args: argparse.Namespace, context: CliContext) -> dict:
277
289
  return context.builder.builder_tool_contract(tool_name=args.tool_name)
278
290
 
279
291
 
292
+ def _handle_icon_catalog(args: argparse.Namespace, context: CliContext) -> dict:
293
+ return context.builder.workspace_icon_catalog_get(profile=args.profile)
294
+
295
+
280
296
  def _handle_member_search(args: argparse.Namespace, context: CliContext) -> dict:
281
297
  return context.builder.member_search(
282
298
  profile=args.profile,
@@ -320,6 +336,10 @@ def _handle_package_get(args: argparse.Namespace, context: CliContext) -> dict:
320
336
  return context.builder.package_get(profile=args.profile, package_id=args.package_id)
321
337
 
322
338
 
339
+ def _handle_package_list(args: argparse.Namespace, context: CliContext) -> dict:
340
+ return context.builder.package_list(profile=args.profile, trial_status=args.trial_status, query=args.query)
341
+
342
+
323
343
  def _handle_package_apply(args: argparse.Namespace, context: CliContext) -> dict:
324
344
  config = load_object_arg(args.config_file, option_name="--config-file")
325
345
  if not isinstance(config, dict):
@@ -557,9 +577,13 @@ def _handle_charts_apply(args: argparse.Namespace, context: CliContext) -> dict:
557
577
 
558
578
 
559
579
  def _handle_portal_apply(args: argparse.Namespace, context: CliContext) -> dict:
580
+ payload = load_object_arg(args.payload_file, option_name="--payload-file") if getattr(args, "payload_file", None) else None
581
+ payload_obj = payload if isinstance(payload, dict) else {}
582
+ effective_dash_name = (args.dash_name or str(payload_obj.get("dash_name") or payload_obj.get("dashName") or payload_obj.get("name") or "")).strip()
583
+ effective_package_id = args.package_id if args.package_id is not None else payload_obj.get("package_id") or payload_obj.get("packageId") or payload_obj.get("package_tag_id")
560
584
  has_dash_key = bool((args.dash_key or "").strip())
561
- has_dash_name = bool((args.dash_name or "").strip())
562
- has_package_id = args.package_id is not None
585
+ has_dash_name = bool(effective_dash_name)
586
+ has_package_id = effective_package_id is not None
563
587
  if has_dash_key and has_package_id:
564
588
  raise_config_error(
565
589
  "portal apply accepts exactly one selector mode.",
@@ -578,6 +602,7 @@ def _handle_portal_apply(args: argparse.Namespace, context: CliContext) -> dict:
578
602
  package_id=args.package_id,
579
603
  publish=bool(args.publish),
580
604
  sections=sections,
605
+ layout_preset=args.layout_preset,
581
606
  visibility=load_object_arg(args.visibility_file, option_name="--visibility-file"),
582
607
  auth=load_object_arg(args.auth_file, option_name="--auth-file"),
583
608
  icon=args.icon,
@@ -585,6 +610,7 @@ def _handle_portal_apply(args: argparse.Namespace, context: CliContext) -> dict:
585
610
  hide_copyright=args.hide_copyright,
586
611
  dash_global_config=load_object_arg(args.dash_global_config_file, option_name="--dash-global-config-file"),
587
612
  config=load_object_arg(args.config_file, option_name="--config-file"),
613
+ payload=payload,
588
614
  )
589
615
 
590
616
 
@@ -12,7 +12,7 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
12
12
 
13
13
  start = export_subparsers.add_parser("start", help="启动导出")
14
14
  start.add_argument("--app-key", required=True)
15
- start.add_argument("--view-id", default="system:all")
15
+ start.add_argument("--view-id", required=True)
16
16
  start.add_argument("--column", dest="columns", action="append", type=int, default=[], help="只导出这些 field_id;不传时导出当前视图全部字段")
17
17
  start.add_argument("--columns-file", help="JSON/YAML list,内容与 --column 语义一致")
18
18
  start.add_argument("--where-file", help="JSON/YAML list,内容与 record list 的 where DSL 一致;内部先查命中 record_id 再走原生导出")
@@ -33,7 +33,7 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
33
33
 
34
34
  direct = export_subparsers.add_parser("direct", help="直接导出并下载")
35
35
  direct.add_argument("--app-key", required=True)
36
- direct.add_argument("--view-id", default="system:all")
36
+ direct.add_argument("--view-id", required=True)
37
37
  direct.add_argument("--column", dest="columns", action="append", type=int, default=[], help="只导出这些 field_id;不传时导出当前视图全部字段")
38
38
  direct.add_argument("--columns-file", help="JSON/YAML list,内容与 --column 语义一致")
39
39
  direct.add_argument("--where-file", help="JSON/YAML list,内容与 record list 的 where DSL 一致;内部先查命中 record_id 再走原生导出")
@@ -13,7 +13,7 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
13
13
  template = import_subparsers.add_parser("template", help="下载导入模板")
14
14
  template.add_argument("--app-key", required=True)
15
15
  template.add_argument("--download-to-path")
16
- template.set_defaults(handler=_handle_template, format_hint="")
16
+ template.set_defaults(handler=_handle_template, format_hint="import_template")
17
17
 
18
18
  verify = import_subparsers.add_parser("verify", help="校验导入文件")
19
19
  verify.add_argument("--app-key", required=True)
@@ -13,17 +13,25 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
13
13
  record_subparsers = parser.add_subparsers(
14
14
  dest="record_command",
15
15
  required=True,
16
- metavar="{schema,list,access,get,insert,update,delete,member-candidates,department-candidates,code-block-run}",
16
+ metavar="{schema,list,access,get,logs,insert,update,delete,member-candidates,department-candidates,code-block-run}",
17
17
  )
18
18
 
19
19
  schema = record_subparsers.add_parser("schema", help="读取记录相关表结构")
20
20
  schema.add_argument("--mode", dest="legacy_mode", help=argparse.SUPPRESS)
21
- schema_subparsers = schema.add_subparsers(dest="record_schema_command")
21
+ schema_subparsers = schema.add_subparsers(
22
+ dest="record_schema_command",
23
+ metavar="{browse,insert,update,import,code-block}",
24
+ )
22
25
  schema.set_defaults(handler=_handle_schema_root, format_hint="")
23
26
 
24
- schema_applicant = schema_subparsers.add_parser("applicant", help="读取申请节点表结构")
27
+ schema_applicant = schema_subparsers.add_parser("applicant", help=argparse.SUPPRESS)
25
28
  schema_applicant.add_argument("--app-key", required=True)
26
29
  schema_applicant.set_defaults(handler=_handle_schema_applicant, format_hint="")
30
+ schema_subparsers._choices_actions = [ # type: ignore[attr-defined]
31
+ action
32
+ for action in schema_subparsers._choices_actions # type: ignore[attr-defined]
33
+ if getattr(action, "dest", None) != "applicant"
34
+ ]
27
35
 
28
36
  schema_browse = schema_subparsers.add_parser("browse", help="读取浏览视图表结构")
29
37
  schema_browse.add_argument("--app-key", required=True)
@@ -37,6 +45,7 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
37
45
  schema_update = schema_subparsers.add_parser("update", help="读取更新记录表结构")
38
46
  schema_update.add_argument("--app-key", required=True)
39
47
  schema_update.add_argument("--record-id", required=True)
48
+ schema_update.add_argument("--view-id")
40
49
  schema_update.set_defaults(handler=_handle_schema_update, format_hint="")
41
50
 
42
51
  schema_import = schema_subparsers.add_parser("import", help="读取导入表结构")
@@ -102,27 +111,36 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
102
111
  get.add_argument("--view-id")
103
112
  get.set_defaults(handler=_handle_get, format_hint="record_get")
104
113
 
114
+ logs = record_subparsers.add_parser("logs", help="读取单条记录全量日志并写入本地 JSONL")
115
+ logs.add_argument("--app-key", required=True)
116
+ logs.add_argument("--record-id", required=True)
117
+ logs.add_argument("--view-id", required=True)
118
+ logs.set_defaults(handler=_handle_logs, format_hint="record_logs")
119
+
105
120
  insert = record_subparsers.add_parser("insert", help="新增记录")
106
121
  insert.add_argument("--app-key", required=True)
107
122
  insert.add_argument("--fields-file", help=argparse.SUPPRESS)
108
123
  insert.add_argument("--items-file")
109
124
  insert.add_argument("--verify-write", action=argparse.BooleanOptionalAction, default=True)
110
- insert.set_defaults(handler=_handle_insert, format_hint="")
125
+ insert.set_defaults(handler=_handle_insert, format_hint="record_write")
111
126
 
112
127
  update = record_subparsers.add_parser("update", help="更新记录")
113
128
  update.add_argument("--app-key", required=True)
114
129
  update.add_argument("--record-id")
115
130
  update.add_argument("--fields-file")
116
131
  update.add_argument("--items-file")
132
+ update.add_argument("--view-id")
117
133
  update.add_argument("--dry-run", action=argparse.BooleanOptionalAction, default=False)
118
134
  update.add_argument("--verify-write", action=argparse.BooleanOptionalAction, default=True)
119
- update.set_defaults(handler=_handle_update, format_hint="")
135
+ update.set_defaults(handler=_handle_update, format_hint="record_write")
120
136
 
121
137
  delete = record_subparsers.add_parser("delete", help="删除记录")
122
138
  delete.add_argument("--app-key", required=True)
123
139
  delete.add_argument("--record-id")
124
140
  delete.add_argument("--record-ids-file")
125
- delete.set_defaults(handler=_handle_delete, format_hint="")
141
+ delete.add_argument("--view-id")
142
+ delete.add_argument("--list-type", dest="legacy_list_type", type=int, help=argparse.SUPPRESS)
143
+ delete.set_defaults(handler=_handle_delete, format_hint="record_delete")
126
144
 
127
145
  analyze = record_subparsers.add_parser("analyze", help=argparse.SUPPRESS)
128
146
  record_subparsers._choices_actions = [ # type: ignore[attr-defined]
@@ -147,6 +165,7 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
147
165
  code_block.add_argument("--app-key", required=True)
148
166
  code_block.add_argument("--record-id", required=True)
149
167
  code_block.add_argument("--code-block-field", required=True)
168
+ code_block.add_argument("--view-id")
150
169
  code_block.add_argument("--role", type=int, default=1)
151
170
  code_block.add_argument("--workflow-node-id", type=int)
152
171
  code_block.add_argument("--answers-file")
@@ -155,7 +174,7 @@ def register(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) ->
155
174
  code_block.add_argument("--apply-writeback", action=argparse.BooleanOptionalAction, default=True)
156
175
  code_block.add_argument("--verify-writeback", action=argparse.BooleanOptionalAction, default=True)
157
176
  code_block.add_argument("--force-refresh-form", action="store_true")
158
- code_block.set_defaults(handler=_handle_code_block_run, format_hint="")
177
+ code_block.set_defaults(handler=_handle_code_block_run, format_hint="code_block_run")
159
178
 
160
179
 
161
180
  def _columns(args: argparse.Namespace) -> list[Any]:
@@ -176,20 +195,20 @@ def _handle_schema_root(args: argparse.Namespace, _context: CliContext) -> dict:
176
195
  mode = (args.legacy_mode or "").strip()
177
196
  if mode:
178
197
  replacement = {
179
- "applicant": "record schema applicant --app-key APP_KEY",
198
+ "applicant": "record schema insert --app-key APP_KEY",
180
199
  "browse": "record schema browse --app-key APP_KEY --view-id VIEW_ID",
181
200
  "insert": "record schema insert --app-key APP_KEY",
182
- "update": "record schema update --app-key APP_KEY --record-id RECORD_ID",
201
+ "update": "record schema update --app-key APP_KEY --record-id RECORD_ID [--view-id VIEW_ID]",
183
202
  "import": "record schema import --app-key APP_KEY",
184
203
  "code-block": "record schema code-block --app-key APP_KEY",
185
- }.get(mode, "record schema <applicant|browse|insert|update|import|code-block> ...")
204
+ }.get(mode, "record schema <browse|insert|update|import|code-block> ...")
186
205
  raise_config_error(
187
206
  "record schema --mode is no longer accepted.",
188
207
  fix_hint=f"Use `{replacement}` instead.",
189
208
  )
190
209
  raise_config_error(
191
210
  "record schema requires an explicit subcommand.",
192
- fix_hint="Use one of: `record schema applicant`, `record schema browse`, `record schema insert`, `record schema update`, `record schema import`, or `record schema code-block`.",
211
+ fix_hint="Use one of: `record schema browse`, `record schema insert`, `record schema update`, `record schema import`, or `record schema code-block`.",
193
212
  )
194
213
 
195
214
 
@@ -218,6 +237,7 @@ def _handle_schema_update(args: argparse.Namespace, context: CliContext) -> dict
218
237
  profile=args.profile,
219
238
  app_key=args.app_key,
220
239
  record_id=args.record_id,
240
+ view_id=args.view_id,
221
241
  )
222
242
 
223
243
 
@@ -328,6 +348,15 @@ def _handle_get(args: argparse.Namespace, context: CliContext) -> dict:
328
348
  )
329
349
 
330
350
 
351
+ def _handle_logs(args: argparse.Namespace, context: CliContext) -> dict:
352
+ return context.record.record_logs_get(
353
+ profile=args.profile,
354
+ app_key=args.app_key,
355
+ record_id=args.record_id,
356
+ view_id=args.view_id,
357
+ )
358
+
359
+
331
360
  def _handle_insert(args: argparse.Namespace, context: CliContext) -> dict:
332
361
  if args.items_file:
333
362
  if args.fields_file:
@@ -367,6 +396,7 @@ def _handle_update(args: argparse.Namespace, context: CliContext) -> dict:
367
396
  record_id=None,
368
397
  fields=None,
369
398
  items=require_list_arg(args.items_file, option_name="--items-file"),
399
+ view_id=args.view_id,
370
400
  dry_run=bool(args.dry_run),
371
401
  verify_write=bool(args.verify_write),
372
402
  )
@@ -385,17 +415,29 @@ def _handle_update(args: argparse.Namespace, context: CliContext) -> dict:
385
415
  app_key=args.app_key,
386
416
  record_id=args.record_id,
387
417
  fields=require_object_arg(args.fields_file, option_name="--fields-file"),
418
+ view_id=args.view_id,
388
419
  verify_write=bool(args.verify_write),
389
420
  )
390
421
 
391
422
 
392
423
  def _handle_delete(args: argparse.Namespace, context: CliContext) -> dict:
424
+ if args.legacy_list_type is not None:
425
+ raise_config_error(
426
+ "record delete no longer accepts list_type.",
427
+ fix_hint="Call `app_get` first and pass an accessible system `view_id`, for example `--view-id system:all`.",
428
+ )
429
+ if not (args.view_id or "").strip():
430
+ raise_config_error(
431
+ "record delete requires --view-id.",
432
+ fix_hint="Use a system view_id from app get accessible_views, for example `--view-id system:all`; custom views are not supported for deletion.",
433
+ )
393
434
  record_ids = load_list_arg(args.record_ids_file, option_name="--record-ids-file")
394
435
  return context.record.record_delete_public(
395
436
  profile=args.profile,
396
437
  app_key=args.app_key,
397
438
  record_id=args.record_id,
398
439
  record_ids=record_ids,
440
+ view_id=args.view_id,
399
441
  )
400
442
 
401
443
 
@@ -431,6 +473,7 @@ def _handle_code_block_run(args: argparse.Namespace, context: CliContext) -> dic
431
473
  app_key=args.app_key,
432
474
  record_id=args.record_id,
433
475
  code_block_field=args.code_block_field,
476
+ view_id=args.view_id,
434
477
  role=args.role,
435
478
  workflow_node_id=args.workflow_node_id,
436
479
  answers=load_list_arg(args.answers_file, option_name="--answers-file"),
@@ -13,7 +13,6 @@ from ..tools.feedback_tools import FeedbackTools
13
13
  from ..tools.file_tools import FileTools
14
14
  from ..tools.import_tools import ImportTools
15
15
  from ..tools.record_tools import RecordTools
16
- from ..tools.repository_dev_tools import RepositoryDevTools
17
16
  from ..tools.resource_read_tools import ResourceReadTools
18
17
  from ..tools.task_context_tools import TaskContextTools
19
18
  from ..tools.workspace_tools import WorkspaceTools
@@ -35,7 +34,6 @@ class CliContext:
35
34
  files: FileTools
36
35
  builder_feedback: FeedbackTools
37
36
  builder: AiBuilderTools
38
- repo: RepositoryDevTools
39
37
 
40
38
  def close(self) -> None:
41
39
  self.backend.close()
@@ -59,5 +57,4 @@ def build_cli_context() -> CliContext:
59
57
  files=FileTools(sessions, backend),
60
58
  builder_feedback=FeedbackTools(backend, mcp_side="App Builder MCP"),
61
59
  builder=AiBuilderTools(sessions, backend),
62
- repo=RepositoryDevTools(sessions, backend),
63
60
  )