@josephyan/qingflow-cli 0.2.0-beta.74 → 0.2.0-beta.75

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.
@@ -0,0 +1,231 @@
1
+ from __future__ import annotations
2
+
3
+ from argparse import Namespace
4
+ from dataclasses import dataclass
5
+
6
+
7
+ USER_DOMAIN = "user"
8
+ BUILDER_DOMAIN = "builder"
9
+
10
+
11
+ @dataclass(frozen=True, slots=True)
12
+ class PublicToolSpec:
13
+ domain: str
14
+ tool_name: str
15
+ method_names: tuple[str, ...] = ()
16
+ cli_route: tuple[str, ...] | None = None
17
+ mcp_public: bool = True
18
+ cli_public: bool = True
19
+ has_contract: bool = False
20
+
21
+ @property
22
+ def trim_key(self) -> str:
23
+ return tool_key(self.domain, self.tool_name)
24
+
25
+
26
+ def tool_key(domain: str, tool_name: str) -> str:
27
+ return f"{domain}:{tool_name}"
28
+
29
+
30
+ USER_PUBLIC_TOOL_SPECS: tuple[PublicToolSpec, ...] = (
31
+ PublicToolSpec(USER_DOMAIN, "auth_login", ("auth_login",), ("auth", "login")),
32
+ PublicToolSpec(USER_DOMAIN, "auth_use_token", ("auth_use_token",), ("auth", "use-token")),
33
+ PublicToolSpec(USER_DOMAIN, "auth_whoami", ("auth_whoami",), ("auth", "whoami")),
34
+ PublicToolSpec(USER_DOMAIN, "auth_logout", ("auth_logout",), ("auth", "logout")),
35
+ PublicToolSpec(USER_DOMAIN, "workspace_list", ("workspace_list",), ("workspace", "list")),
36
+ PublicToolSpec(USER_DOMAIN, "workspace_select", ("workspace_select",), ("workspace", "select")),
37
+ PublicToolSpec(USER_DOMAIN, "app_list", ("app_list",), ("app", "list")),
38
+ PublicToolSpec(USER_DOMAIN, "app_search", ("app_search",), ("app", "search")),
39
+ PublicToolSpec(USER_DOMAIN, "app_get", ("app_get",), ("app", "get")),
40
+ PublicToolSpec(USER_DOMAIN, "portal_list", ("portal_list",), ("portal", "list")),
41
+ PublicToolSpec(USER_DOMAIN, "portal_get", ("portal_get",), ("portal", "get")),
42
+ PublicToolSpec(USER_DOMAIN, "view_get", ("view_get",), ("view", "get")),
43
+ PublicToolSpec(USER_DOMAIN, "chart_get", ("chart_get",), ("chart", "get")),
44
+ PublicToolSpec(USER_DOMAIN, "file_get_upload_info", ("file_get_upload_info",), cli_public=False),
45
+ PublicToolSpec(USER_DOMAIN, "file_upload_local", ("file_upload_local",), cli_public=False),
46
+ PublicToolSpec(USER_DOMAIN, "feedback_submit", ("feedback_submit",), cli_public=False),
47
+ PublicToolSpec(
48
+ USER_DOMAIN,
49
+ "record_schema_get",
50
+ cli_route=("record", "schema", "applicant"),
51
+ mcp_public=False,
52
+ ),
53
+ PublicToolSpec(
54
+ USER_DOMAIN,
55
+ "record_browse_schema_get",
56
+ ("record_browse_schema_get_public",),
57
+ ("record", "schema", "browse"),
58
+ ),
59
+ PublicToolSpec(
60
+ USER_DOMAIN,
61
+ "record_insert_schema_get",
62
+ ("record_insert_schema_get_public",),
63
+ ("record", "schema", "insert"),
64
+ ),
65
+ PublicToolSpec(
66
+ USER_DOMAIN,
67
+ "record_update_schema_get",
68
+ ("record_update_schema_get_public",),
69
+ ("record", "schema", "update"),
70
+ ),
71
+ PublicToolSpec(USER_DOMAIN, "record_import_schema_get", ("record_import_schema_get",), ("record", "schema", "import")),
72
+ PublicToolSpec(
73
+ USER_DOMAIN,
74
+ "record_code_block_schema_get",
75
+ ("record_code_block_schema_get_public",),
76
+ ("record", "schema", "code-block"),
77
+ ),
78
+ PublicToolSpec(USER_DOMAIN, "record_member_candidates", ("record_member_candidates",), cli_public=False),
79
+ PublicToolSpec(USER_DOMAIN, "record_department_candidates", ("record_department_candidates",), cli_public=False),
80
+ PublicToolSpec(USER_DOMAIN, "record_analyze", ("record_analyze",), ("record", "analyze")),
81
+ PublicToolSpec(USER_DOMAIN, "record_list", ("record_list",), ("record", "list")),
82
+ PublicToolSpec(USER_DOMAIN, "record_get", ("record_get_public",), ("record", "get")),
83
+ PublicToolSpec(USER_DOMAIN, "record_insert", ("record_insert_public",), ("record", "insert")),
84
+ PublicToolSpec(USER_DOMAIN, "record_update", ("record_update_public",), ("record", "update")),
85
+ PublicToolSpec(USER_DOMAIN, "record_delete", ("record_delete_public",), ("record", "delete")),
86
+ PublicToolSpec(USER_DOMAIN, "record_import_template_get", ("record_import_template_get",), ("import", "template")),
87
+ PublicToolSpec(USER_DOMAIN, "record_import_verify", ("record_import_verify",), ("import", "verify")),
88
+ PublicToolSpec(USER_DOMAIN, "record_import_repair_local", ("record_import_repair_local",), ("import", "repair")),
89
+ PublicToolSpec(USER_DOMAIN, "record_import_start", ("record_import_start",), ("import", "start")),
90
+ PublicToolSpec(USER_DOMAIN, "record_import_status_get", ("record_import_status_get",), ("import", "status")),
91
+ PublicToolSpec(USER_DOMAIN, "record_code_block_run", ("record_code_block_run",), ("record", "code-block-run")),
92
+ PublicToolSpec(USER_DOMAIN, "task_list", ("task_list",), ("task", "list")),
93
+ PublicToolSpec(USER_DOMAIN, "task_get", ("task_get",), ("task", "get")),
94
+ PublicToolSpec(USER_DOMAIN, "task_save_only", ("task_save_only",), ("task", "save-only")),
95
+ PublicToolSpec(USER_DOMAIN, "task_action_execute", ("task_action_execute",), ("task", "action")),
96
+ PublicToolSpec(USER_DOMAIN, "task_associated_report_detail_get", ("task_associated_report_detail_get",), cli_public=False),
97
+ PublicToolSpec(USER_DOMAIN, "task_workflow_log_get", ("task_workflow_log_get",), ("task", "log")),
98
+ PublicToolSpec(USER_DOMAIN, "directory_search", ("directory_search",), cli_public=False),
99
+ PublicToolSpec(USER_DOMAIN, "directory_list_internal_users", ("directory_list_internal_users",), cli_public=False),
100
+ PublicToolSpec(USER_DOMAIN, "directory_list_all_internal_users", ("directory_list_all_internal_users",), cli_public=False),
101
+ PublicToolSpec(USER_DOMAIN, "directory_list_internal_departments", ("directory_list_internal_departments",), cli_public=False),
102
+ PublicToolSpec(USER_DOMAIN, "directory_list_all_departments", ("directory_list_all_departments",), cli_public=False),
103
+ PublicToolSpec(USER_DOMAIN, "directory_list_sub_departments", ("directory_list_sub_departments",), cli_public=False),
104
+ PublicToolSpec(USER_DOMAIN, "directory_list_external_members", ("directory_list_external_members",), cli_public=False),
105
+ )
106
+
107
+
108
+ BUILDER_PUBLIC_TOOL_SPECS: tuple[PublicToolSpec, ...] = (
109
+ PublicToolSpec(BUILDER_DOMAIN, "auth_login", ("auth_login",), ("builder", "auth", "login"), cli_public=False),
110
+ PublicToolSpec(BUILDER_DOMAIN, "auth_use_token", ("auth_use_token",), ("builder", "auth", "use-token"), cli_public=False),
111
+ PublicToolSpec(BUILDER_DOMAIN, "auth_whoami", ("auth_whoami",), ("builder", "auth", "whoami"), cli_public=False),
112
+ PublicToolSpec(BUILDER_DOMAIN, "auth_logout", ("auth_logout",), ("builder", "auth", "logout"), cli_public=False),
113
+ PublicToolSpec(BUILDER_DOMAIN, "workspace_list", ("workspace_list",), ("builder", "workspace", "list"), cli_public=False),
114
+ PublicToolSpec(BUILDER_DOMAIN, "workspace_select", ("workspace_select",), ("builder", "workspace", "select"), cli_public=False),
115
+ PublicToolSpec(BUILDER_DOMAIN, "file_upload_local", ("file_upload_local",), ("builder", "file", "upload-local"), has_contract=True),
116
+ PublicToolSpec(BUILDER_DOMAIN, "feedback_submit", ("feedback_submit",), ("builder", "feedback", "submit"), has_contract=True),
117
+ PublicToolSpec(BUILDER_DOMAIN, "package_list", ("package_list",), ("builder", "package", "list"), has_contract=True),
118
+ PublicToolSpec(BUILDER_DOMAIN, "package_resolve", ("package_resolve",), ("builder", "package", "resolve"), has_contract=True),
119
+ PublicToolSpec(BUILDER_DOMAIN, "builder_tool_contract", ("builder_tool_contract",), ("builder", "contract"), has_contract=False),
120
+ PublicToolSpec(BUILDER_DOMAIN, "package_create", ("package_create",), ("builder", "package", "create"), has_contract=True),
121
+ PublicToolSpec(BUILDER_DOMAIN, "solution_install", ("solution_install",), ("builder", "solution", "install"), has_contract=True),
122
+ PublicToolSpec(BUILDER_DOMAIN, "member_search", ("member_search",), ("builder", "member", "search"), has_contract=True),
123
+ PublicToolSpec(BUILDER_DOMAIN, "role_search", ("role_search",), ("builder", "role", "search"), has_contract=True),
124
+ PublicToolSpec(BUILDER_DOMAIN, "role_create", ("role_create",), ("builder", "role", "create"), has_contract=True),
125
+ PublicToolSpec(BUILDER_DOMAIN, "package_attach_app", ("package_attach_app",), ("builder", "package", "attach-app"), has_contract=True),
126
+ PublicToolSpec(BUILDER_DOMAIN, "app_release_edit_lock_if_mine", ("app_release_edit_lock_if_mine",), ("builder", "app", "release-edit-lock-if-mine"), has_contract=True),
127
+ PublicToolSpec(BUILDER_DOMAIN, "app_resolve", ("app_resolve",), ("builder", "app", "resolve"), has_contract=True),
128
+ PublicToolSpec(BUILDER_DOMAIN, "app_custom_button_list", ("app_custom_button_list",), ("builder", "button", "list"), has_contract=True),
129
+ PublicToolSpec(BUILDER_DOMAIN, "app_custom_button_get", ("app_custom_button_get",), ("builder", "button", "get"), has_contract=True),
130
+ PublicToolSpec(BUILDER_DOMAIN, "app_custom_button_create", ("app_custom_button_create",), ("builder", "button", "create"), has_contract=True),
131
+ PublicToolSpec(BUILDER_DOMAIN, "app_custom_button_update", ("app_custom_button_update",), ("builder", "button", "update"), has_contract=True),
132
+ PublicToolSpec(BUILDER_DOMAIN, "app_custom_button_delete", ("app_custom_button_delete",), ("builder", "button", "delete"), has_contract=True),
133
+ PublicToolSpec(BUILDER_DOMAIN, "app_get", ("app_get",), ("builder", "app", "get", "summary"), has_contract=True),
134
+ PublicToolSpec(BUILDER_DOMAIN, "app_get_fields", ("app_get_fields",), ("builder", "app", "get", "fields"), has_contract=True),
135
+ PublicToolSpec(BUILDER_DOMAIN, "app_repair_code_blocks", ("app_repair_code_blocks",), ("builder", "app", "repair-code-blocks"), has_contract=True),
136
+ PublicToolSpec(BUILDER_DOMAIN, "app_get_layout", ("app_get_layout",), ("builder", "app", "get", "layout"), has_contract=True),
137
+ PublicToolSpec(BUILDER_DOMAIN, "app_get_views", ("app_get_views",), ("builder", "app", "get", "views"), has_contract=True),
138
+ PublicToolSpec(BUILDER_DOMAIN, "app_get_flow", ("app_get_flow",), ("builder", "app", "get", "flow"), has_contract=True),
139
+ PublicToolSpec(BUILDER_DOMAIN, "app_get_charts", ("app_get_charts",), ("builder", "app", "get", "charts"), has_contract=True),
140
+ PublicToolSpec(BUILDER_DOMAIN, "portal_list", ("portal_list",), ("builder", "portal", "list"), has_contract=True),
141
+ PublicToolSpec(BUILDER_DOMAIN, "portal_get", ("portal_get",), ("builder", "portal", "get"), has_contract=True),
142
+ PublicToolSpec(BUILDER_DOMAIN, "view_get", ("view_get",), ("builder", "view", "get"), has_contract=True),
143
+ PublicToolSpec(BUILDER_DOMAIN, "chart_get", ("chart_get",), ("builder", "chart", "get"), has_contract=True),
144
+ PublicToolSpec(BUILDER_DOMAIN, "app_schema_apply", ("app_schema_apply",), ("builder", "schema", "apply"), has_contract=True),
145
+ PublicToolSpec(BUILDER_DOMAIN, "app_layout_apply", ("app_layout_apply",), ("builder", "layout", "apply"), has_contract=True),
146
+ PublicToolSpec(BUILDER_DOMAIN, "app_flow_apply", ("app_flow_apply",), ("builder", "flow", "apply"), has_contract=True),
147
+ PublicToolSpec(BUILDER_DOMAIN, "app_views_apply", ("app_views_apply",), ("builder", "views", "apply"), has_contract=True),
148
+ PublicToolSpec(BUILDER_DOMAIN, "app_charts_apply", ("app_charts_apply",), ("builder", "charts", "apply"), has_contract=True),
149
+ PublicToolSpec(BUILDER_DOMAIN, "portal_apply", ("portal_apply",), ("builder", "portal", "apply"), has_contract=True),
150
+ PublicToolSpec(BUILDER_DOMAIN, "app_publish_verify", ("app_publish_verify",), ("builder", "publish", "verify"), has_contract=True),
151
+ )
152
+
153
+
154
+ ALL_PUBLIC_TOOL_SPECS: tuple[PublicToolSpec, ...] = USER_PUBLIC_TOOL_SPECS + BUILDER_PUBLIC_TOOL_SPECS
155
+ PUBLIC_TOOL_BY_KEY: dict[str, PublicToolSpec] = {spec.trim_key: spec for spec in ALL_PUBLIC_TOOL_SPECS}
156
+ PUBLIC_TOOL_BY_CLI_ROUTE: dict[tuple[str, ...], PublicToolSpec] = {
157
+ spec.cli_route: spec
158
+ for spec in ALL_PUBLIC_TOOL_SPECS
159
+ if spec.cli_public and spec.cli_route is not None
160
+ }
161
+
162
+
163
+ def public_tool_specs(domain: str | None = None) -> tuple[PublicToolSpec, ...]:
164
+ if domain is None:
165
+ return ALL_PUBLIC_TOOL_SPECS
166
+ return tuple(spec for spec in ALL_PUBLIC_TOOL_SPECS if spec.domain == domain)
167
+
168
+
169
+ def public_mcp_tool_names(domain: str) -> set[str]:
170
+ return {spec.tool_name for spec in public_tool_specs(domain) if spec.mcp_public}
171
+
172
+
173
+ def public_builder_contract_tool_names() -> list[str]:
174
+ return sorted(
175
+ spec.tool_name
176
+ for spec in BUILDER_PUBLIC_TOOL_SPECS
177
+ if spec.has_contract and (spec.mcp_public or spec.cli_public)
178
+ )
179
+
180
+
181
+ def server_method_map(domain: str) -> dict[str, str]:
182
+ mapping: dict[str, str] = {}
183
+ for spec in public_tool_specs(domain):
184
+ if not spec.mcp_public:
185
+ continue
186
+ for method_name in spec.method_names:
187
+ mapping[method_name] = spec.trim_key
188
+ return mapping
189
+
190
+
191
+ def cli_trim_key_from_namespace(args: Namespace) -> str | None:
192
+ route = cli_route_from_namespace(args)
193
+ if route is None:
194
+ return None
195
+ spec = PUBLIC_TOOL_BY_CLI_ROUTE.get(route)
196
+ return spec.trim_key if spec is not None else None
197
+
198
+
199
+ def cli_route_from_namespace(args: Namespace) -> tuple[str, ...] | None:
200
+ command = getattr(args, "command", None)
201
+ if not isinstance(command, str) or not command:
202
+ return None
203
+ command = "builder" if command == "build" else command
204
+ if command == "record":
205
+ record_command = getattr(args, "record_command", None)
206
+ if record_command == "schema":
207
+ schema_command = getattr(args, "record_schema_command", None)
208
+ return (command, "schema", schema_command) if isinstance(schema_command, str) and schema_command else None
209
+ return (command, record_command) if isinstance(record_command, str) and record_command else None
210
+ if command == "task":
211
+ task_command = getattr(args, "task_command", None)
212
+ return (command, task_command) if isinstance(task_command, str) and task_command else None
213
+ if command != "builder":
214
+ child_attr = f"{command}_command"
215
+ child = getattr(args, child_attr, None)
216
+ return (command, child) if isinstance(child, str) and child else None
217
+
218
+ builder_command = getattr(args, "builder_command", None)
219
+ if not isinstance(builder_command, str) or not builder_command:
220
+ return None
221
+ if builder_command == "contract":
222
+ return ("builder", "contract")
223
+ if builder_command == "app":
224
+ app_command = getattr(args, "builder_app_command", None)
225
+ if app_command == "get":
226
+ section = getattr(args, "builder_app_get_section", "summary") or "summary"
227
+ return ("builder", "app", "get", str(section))
228
+ return ("builder", "app", app_command) if isinstance(app_command, str) and app_command else None
229
+ child_attr = f"builder_{builder_command.replace('-', '_')}_command"
230
+ child = getattr(args, child_attr, None)
231
+ return ("builder", builder_command, child) if isinstance(child, str) and child else None
@@ -5,11 +5,17 @@ from copy import deepcopy
5
5
  from functools import wraps
6
6
  from typing import Any, Callable
7
7
 
8
+ from .public_surface import (
9
+ BUILDER_DOMAIN,
10
+ USER_DOMAIN,
11
+ cli_trim_key_from_namespace,
12
+ server_method_map,
13
+ tool_key,
14
+ )
15
+
8
16
 
9
17
  JSONObject = dict[str, Any]
10
18
  TransformFn = Callable[[JSONObject], None]
11
- USER_DOMAIN = "user"
12
- BUILDER_DOMAIN = "builder"
13
19
 
14
20
 
15
21
  COMMON_SUCCESS_DROP_TOP = {
@@ -47,10 +53,6 @@ COMMON_ERROR_DROP_TOP = {
47
53
  SUCCESS_POLICY_BY_TOOL: dict[str, TransformFn] = {}
48
54
 
49
55
 
50
- def _tool_key(domain: str, tool_name: str) -> str:
51
- return f"{domain}:{tool_name}"
52
-
53
-
54
56
  def trim_public_response(tool_name: str | None, payload: dict[str, Any]) -> dict[str, Any]:
55
57
  if not isinstance(payload, dict):
56
58
  return payload
@@ -100,248 +102,11 @@ def wrap_trimmed_methods(instance: object, method_map: dict[str, str]) -> object
100
102
 
101
103
 
102
104
  def resolve_cli_tool_name(args: Any) -> str | None:
103
- command = getattr(args, "command", None)
104
- if command == "auth":
105
- return {
106
- "login": _tool_key(USER_DOMAIN, "auth_login"),
107
- "use-token": _tool_key(USER_DOMAIN, "auth_use_token"),
108
- "whoami": _tool_key(USER_DOMAIN, "auth_whoami"),
109
- "logout": _tool_key(USER_DOMAIN, "auth_logout"),
110
- }.get(getattr(args, "auth_command", None))
111
- if command == "workspace":
112
- return {
113
- "list": _tool_key(USER_DOMAIN, "workspace_list"),
114
- "select": _tool_key(USER_DOMAIN, "workspace_select"),
115
- }.get(getattr(args, "workspace_command", None))
116
- if command == "app":
117
- return {
118
- "list": _tool_key(USER_DOMAIN, "app_list"),
119
- "search": _tool_key(USER_DOMAIN, "app_search"),
120
- "get": _tool_key(USER_DOMAIN, "app_get"),
121
- }.get(getattr(args, "app_command", None))
122
- if command == "portal":
123
- return {
124
- "list": _tool_key(USER_DOMAIN, "portal_list"),
125
- "get": _tool_key(USER_DOMAIN, "portal_get"),
126
- }.get(getattr(args, "portal_command", None))
127
- if command == "view":
128
- return {
129
- "get": _tool_key(USER_DOMAIN, "view_get"),
130
- }.get(getattr(args, "view_command", None))
131
- if command == "chart":
132
- return {
133
- "get": _tool_key(USER_DOMAIN, "chart_get"),
134
- }.get(getattr(args, "chart_command", None))
135
- if command == "record":
136
- record_command = getattr(args, "record_command", None)
137
- if record_command == "schema":
138
- return {
139
- "applicant": _tool_key(USER_DOMAIN, "record_schema_get"),
140
- "browse": _tool_key(USER_DOMAIN, "record_browse_schema_get"),
141
- "insert": _tool_key(USER_DOMAIN, "record_insert_schema_get"),
142
- "update": _tool_key(USER_DOMAIN, "record_update_schema_get"),
143
- "import": _tool_key(USER_DOMAIN, "record_import_schema_get"),
144
- "code-block": _tool_key(USER_DOMAIN, "record_code_block_schema_get"),
145
- }.get(getattr(args, "record_schema_command", None))
146
- return {
147
- "list": _tool_key(USER_DOMAIN, "record_list"),
148
- "get": _tool_key(USER_DOMAIN, "record_get"),
149
- "insert": _tool_key(USER_DOMAIN, "record_insert"),
150
- "update": _tool_key(USER_DOMAIN, "record_update"),
151
- "delete": _tool_key(USER_DOMAIN, "record_delete"),
152
- "analyze": _tool_key(USER_DOMAIN, "record_analyze"),
153
- "code-block-run": _tool_key(USER_DOMAIN, "record_code_block_run"),
154
- }.get(record_command)
155
- if command == "import":
156
- return {
157
- "template": _tool_key(USER_DOMAIN, "record_import_template_get"),
158
- "verify": _tool_key(USER_DOMAIN, "record_import_verify"),
159
- "repair": _tool_key(USER_DOMAIN, "record_import_repair_local"),
160
- "start": _tool_key(USER_DOMAIN, "record_import_start"),
161
- "status": _tool_key(USER_DOMAIN, "record_import_status_get"),
162
- }.get(getattr(args, "import_command", None))
163
- if command == "task":
164
- return {
165
- "list": _tool_key(USER_DOMAIN, "task_list"),
166
- "get": _tool_key(USER_DOMAIN, "task_get"),
167
- "action": _tool_key(USER_DOMAIN, "task_action_execute"),
168
- "log": _tool_key(USER_DOMAIN, "task_workflow_log_get"),
169
- }.get(getattr(args, "task_command", None))
170
- if command not in {"builder", "build"}:
171
- return None
172
- builder_command = getattr(args, "builder_command", None)
173
- if builder_command == "file":
174
- return {
175
- "upload-local": _tool_key(BUILDER_DOMAIN, "file_upload_local"),
176
- }.get(getattr(args, "builder_file_command", None))
177
- if builder_command == "feedback":
178
- return {
179
- "submit": _tool_key(BUILDER_DOMAIN, "feedback_submit"),
180
- }.get(getattr(args, "builder_feedback_command", None))
181
- if builder_command == "contract":
182
- return _tool_key(BUILDER_DOMAIN, "builder_tool_contract")
183
- if builder_command == "member":
184
- return {
185
- "search": _tool_key(BUILDER_DOMAIN, "member_search"),
186
- }.get(getattr(args, "builder_member_command", None))
187
- if builder_command == "role":
188
- return {
189
- "search": _tool_key(BUILDER_DOMAIN, "role_search"),
190
- "create": _tool_key(BUILDER_DOMAIN, "role_create"),
191
- }.get(getattr(args, "builder_role_command", None))
192
- if builder_command == "package":
193
- return {
194
- "list": _tool_key(BUILDER_DOMAIN, "package_list"),
195
- "resolve": _tool_key(BUILDER_DOMAIN, "package_resolve"),
196
- "create": _tool_key(BUILDER_DOMAIN, "package_create"),
197
- "attach-app": _tool_key(BUILDER_DOMAIN, "package_attach_app"),
198
- }.get(getattr(args, "builder_package_command", None))
199
- if builder_command == "app":
200
- app_command = getattr(args, "builder_app_command", None)
201
- if app_command == "get":
202
- return {
203
- "summary": _tool_key(BUILDER_DOMAIN, "app_get"),
204
- "fields": _tool_key(BUILDER_DOMAIN, "app_get_fields"),
205
- "layout": _tool_key(BUILDER_DOMAIN, "app_get_layout"),
206
- "views": _tool_key(BUILDER_DOMAIN, "app_get_views"),
207
- "flow": _tool_key(BUILDER_DOMAIN, "app_get_flow"),
208
- "charts": _tool_key(BUILDER_DOMAIN, "app_get_charts"),
209
- }.get(getattr(args, "builder_app_get_section", "summary"))
210
- return {
211
- "resolve": _tool_key(BUILDER_DOMAIN, "app_resolve"),
212
- "release-edit-lock-if-mine": _tool_key(BUILDER_DOMAIN, "app_release_edit_lock_if_mine"),
213
- "repair-code-blocks": _tool_key(BUILDER_DOMAIN, "app_repair_code_blocks"),
214
- }.get(app_command)
215
- if builder_command == "button":
216
- return {
217
- "list": _tool_key(BUILDER_DOMAIN, "app_custom_button_list"),
218
- "get": _tool_key(BUILDER_DOMAIN, "app_custom_button_get"),
219
- "create": _tool_key(BUILDER_DOMAIN, "app_custom_button_create"),
220
- "update": _tool_key(BUILDER_DOMAIN, "app_custom_button_update"),
221
- "delete": _tool_key(BUILDER_DOMAIN, "app_custom_button_delete"),
222
- }.get(getattr(args, "builder_button_command", None))
223
- if builder_command == "portal":
224
- return {
225
- "list": _tool_key(BUILDER_DOMAIN, "portal_list"),
226
- "get": _tool_key(BUILDER_DOMAIN, "portal_get"),
227
- "apply": _tool_key(BUILDER_DOMAIN, "portal_apply"),
228
- }.get(getattr(args, "builder_portal_command", None))
229
- if builder_command == "view":
230
- return {
231
- "get": _tool_key(BUILDER_DOMAIN, "view_get"),
232
- }.get(getattr(args, "builder_view_command", None))
233
- if builder_command == "chart":
234
- return {
235
- "get": _tool_key(BUILDER_DOMAIN, "chart_get"),
236
- }.get(getattr(args, "builder_chart_command", None))
237
- if builder_command == "schema":
238
- return {"apply": _tool_key(BUILDER_DOMAIN, "app_schema_apply")}.get(getattr(args, "builder_schema_command", None))
239
- if builder_command == "layout":
240
- return {"apply": _tool_key(BUILDER_DOMAIN, "app_layout_apply")}.get(getattr(args, "builder_layout_command", None))
241
- if builder_command == "views":
242
- return {"apply": _tool_key(BUILDER_DOMAIN, "app_views_apply")}.get(getattr(args, "builder_views_command", None))
243
- if builder_command == "flow":
244
- return {"apply": _tool_key(BUILDER_DOMAIN, "app_flow_apply")}.get(getattr(args, "builder_flow_command", None))
245
- if builder_command == "charts":
246
- return {"apply": _tool_key(BUILDER_DOMAIN, "app_charts_apply")}.get(getattr(args, "builder_charts_command", None))
247
- if builder_command == "publish":
248
- return {"verify": _tool_key(BUILDER_DOMAIN, "app_publish_verify")}.get(getattr(args, "builder_publish_command", None))
249
- return None
250
-
251
-
252
- USER_SERVER_METHOD_MAP = {
253
- "auth_login": _tool_key(USER_DOMAIN, "auth_login"),
254
- "auth_use_token": _tool_key(USER_DOMAIN, "auth_use_token"),
255
- "auth_whoami": _tool_key(USER_DOMAIN, "auth_whoami"),
256
- "auth_logout": _tool_key(USER_DOMAIN, "auth_logout"),
257
- "workspace_list": _tool_key(USER_DOMAIN, "workspace_list"),
258
- "workspace_select": _tool_key(USER_DOMAIN, "workspace_select"),
259
- "app_list": _tool_key(USER_DOMAIN, "app_list"),
260
- "app_search": _tool_key(USER_DOMAIN, "app_search"),
261
- "app_get": _tool_key(USER_DOMAIN, "app_get"),
262
- "portal_list": _tool_key(USER_DOMAIN, "portal_list"),
263
- "portal_get": _tool_key(USER_DOMAIN, "portal_get"),
264
- "view_get": _tool_key(USER_DOMAIN, "view_get"),
265
- "chart_get": _tool_key(USER_DOMAIN, "chart_get"),
266
- "file_get_upload_info": _tool_key(USER_DOMAIN, "file_get_upload_info"),
267
- "file_upload_local": _tool_key(USER_DOMAIN, "file_upload_local"),
268
- "feedback_submit": _tool_key(USER_DOMAIN, "feedback_submit"),
269
- "record_import_schema_get": _tool_key(USER_DOMAIN, "record_import_schema_get"),
270
- "record_import_template_get": _tool_key(USER_DOMAIN, "record_import_template_get"),
271
- "record_import_verify": _tool_key(USER_DOMAIN, "record_import_verify"),
272
- "record_import_repair_local": _tool_key(USER_DOMAIN, "record_import_repair_local"),
273
- "record_import_start": _tool_key(USER_DOMAIN, "record_import_start"),
274
- "record_import_status_get": _tool_key(USER_DOMAIN, "record_import_status_get"),
275
- "record_insert_schema_get_public": _tool_key(USER_DOMAIN, "record_insert_schema_get"),
276
- "record_member_candidates": _tool_key(USER_DOMAIN, "record_member_candidates"),
277
- "record_department_candidates": _tool_key(USER_DOMAIN, "record_department_candidates"),
278
- "record_analyze": _tool_key(USER_DOMAIN, "record_analyze"),
279
- "record_list": _tool_key(USER_DOMAIN, "record_list"),
280
- "record_get_public": _tool_key(USER_DOMAIN, "record_get"),
281
- "record_browse_schema_get_public": _tool_key(USER_DOMAIN, "record_browse_schema_get"),
282
- "record_update_schema_get_public": _tool_key(USER_DOMAIN, "record_update_schema_get"),
283
- "record_insert_public": _tool_key(USER_DOMAIN, "record_insert"),
284
- "record_update_public": _tool_key(USER_DOMAIN, "record_update"),
285
- "record_delete_public": _tool_key(USER_DOMAIN, "record_delete"),
286
- "record_code_block_schema_get_public": _tool_key(USER_DOMAIN, "record_code_block_schema_get"),
287
- "record_code_block_run": _tool_key(USER_DOMAIN, "record_code_block_run"),
288
- "task_list": _tool_key(USER_DOMAIN, "task_list"),
289
- "task_get": _tool_key(USER_DOMAIN, "task_get"),
290
- "task_action_execute": _tool_key(USER_DOMAIN, "task_action_execute"),
291
- "task_associated_report_detail_get": _tool_key(USER_DOMAIN, "task_associated_report_detail_get"),
292
- "task_workflow_log_get": _tool_key(USER_DOMAIN, "task_workflow_log_get"),
293
- "directory_search": _tool_key(USER_DOMAIN, "directory_search"),
294
- "directory_list_internal_users": _tool_key(USER_DOMAIN, "directory_list_internal_users"),
295
- "directory_list_all_internal_users": _tool_key(USER_DOMAIN, "directory_list_all_internal_users"),
296
- "directory_list_internal_departments": _tool_key(USER_DOMAIN, "directory_list_internal_departments"),
297
- "directory_list_all_departments": _tool_key(USER_DOMAIN, "directory_list_all_departments"),
298
- "directory_list_sub_departments": _tool_key(USER_DOMAIN, "directory_list_sub_departments"),
299
- "directory_list_external_members": _tool_key(USER_DOMAIN, "directory_list_external_members"),
300
- }
105
+ return cli_trim_key_from_namespace(args)
301
106
 
302
- BUILDER_SERVER_METHOD_MAP = {
303
- "auth_login": _tool_key(BUILDER_DOMAIN, "auth_login"),
304
- "auth_use_token": _tool_key(BUILDER_DOMAIN, "auth_use_token"),
305
- "auth_whoami": _tool_key(BUILDER_DOMAIN, "auth_whoami"),
306
- "auth_logout": _tool_key(BUILDER_DOMAIN, "auth_logout"),
307
- "workspace_list": _tool_key(BUILDER_DOMAIN, "workspace_list"),
308
- "workspace_select": _tool_key(BUILDER_DOMAIN, "workspace_select"),
309
- "file_upload_local": _tool_key(BUILDER_DOMAIN, "file_upload_local"),
310
- "feedback_submit": _tool_key(BUILDER_DOMAIN, "feedback_submit"),
311
- "package_list": _tool_key(BUILDER_DOMAIN, "package_list"),
312
- "package_resolve": _tool_key(BUILDER_DOMAIN, "package_resolve"),
313
- "builder_tool_contract": _tool_key(BUILDER_DOMAIN, "builder_tool_contract"),
314
- "package_create": _tool_key(BUILDER_DOMAIN, "package_create"),
315
- "member_search": _tool_key(BUILDER_DOMAIN, "member_search"),
316
- "role_search": _tool_key(BUILDER_DOMAIN, "role_search"),
317
- "role_create": _tool_key(BUILDER_DOMAIN, "role_create"),
318
- "package_attach_app": _tool_key(BUILDER_DOMAIN, "package_attach_app"),
319
- "app_release_edit_lock_if_mine": _tool_key(BUILDER_DOMAIN, "app_release_edit_lock_if_mine"),
320
- "app_resolve": _tool_key(BUILDER_DOMAIN, "app_resolve"),
321
- "app_custom_button_list": _tool_key(BUILDER_DOMAIN, "app_custom_button_list"),
322
- "app_custom_button_get": _tool_key(BUILDER_DOMAIN, "app_custom_button_get"),
323
- "app_custom_button_create": _tool_key(BUILDER_DOMAIN, "app_custom_button_create"),
324
- "app_custom_button_update": _tool_key(BUILDER_DOMAIN, "app_custom_button_update"),
325
- "app_custom_button_delete": _tool_key(BUILDER_DOMAIN, "app_custom_button_delete"),
326
- "app_get": _tool_key(BUILDER_DOMAIN, "app_get"),
327
- "app_get_fields": _tool_key(BUILDER_DOMAIN, "app_get_fields"),
328
- "app_repair_code_blocks": _tool_key(BUILDER_DOMAIN, "app_repair_code_blocks"),
329
- "app_get_layout": _tool_key(BUILDER_DOMAIN, "app_get_layout"),
330
- "app_get_views": _tool_key(BUILDER_DOMAIN, "app_get_views"),
331
- "app_get_flow": _tool_key(BUILDER_DOMAIN, "app_get_flow"),
332
- "app_get_charts": _tool_key(BUILDER_DOMAIN, "app_get_charts"),
333
- "portal_list": _tool_key(BUILDER_DOMAIN, "portal_list"),
334
- "portal_get": _tool_key(BUILDER_DOMAIN, "portal_get"),
335
- "view_get": _tool_key(BUILDER_DOMAIN, "view_get"),
336
- "chart_get": _tool_key(BUILDER_DOMAIN, "chart_get"),
337
- "app_schema_apply": _tool_key(BUILDER_DOMAIN, "app_schema_apply"),
338
- "app_layout_apply": _tool_key(BUILDER_DOMAIN, "app_layout_apply"),
339
- "app_flow_apply": _tool_key(BUILDER_DOMAIN, "app_flow_apply"),
340
- "app_views_apply": _tool_key(BUILDER_DOMAIN, "app_views_apply"),
341
- "app_charts_apply": _tool_key(BUILDER_DOMAIN, "app_charts_apply"),
342
- "portal_apply": _tool_key(BUILDER_DOMAIN, "portal_apply"),
343
- "app_publish_verify": _tool_key(BUILDER_DOMAIN, "app_publish_verify"),
344
- }
107
+
108
+ USER_SERVER_METHOD_MAP = server_method_map(USER_DOMAIN)
109
+ BUILDER_SERVER_METHOD_MAP = server_method_map(BUILDER_DOMAIN)
345
110
 
346
111
 
347
112
  def _wrap_callable(original: Callable[..., Any], tool_name: str) -> Callable[..., Any]:
@@ -602,7 +367,7 @@ def _trim_builder_list_like(payload: JSONObject) -> None:
602
367
  def _register_policy(domains: tuple[str, ...], names: tuple[str, ...], transform: TransformFn) -> None:
603
368
  for domain in domains:
604
369
  for name in names:
605
- SUCCESS_POLICY_BY_TOOL[_tool_key(domain, name)] = transform
370
+ SUCCESS_POLICY_BY_TOOL[tool_key(domain, name)] = transform
606
371
 
607
372
 
608
373
  _register_policy((USER_DOMAIN, BUILDER_DOMAIN), ("auth_login", "auth_use_token", "auth_whoami"), _trim_auth_payload)
@@ -648,6 +413,7 @@ _register_policy(
648
413
  (USER_DOMAIN,),
649
414
  (
650
415
  "task_get",
416
+ "task_save_only",
651
417
  "task_action_execute",
652
418
  "task_associated_report_detail_get",
653
419
  "task_workflow_log_get",
@@ -683,6 +449,7 @@ _register_policy(
683
449
  "package_list",
684
450
  "package_resolve",
685
451
  "builder_tool_contract",
452
+ "solution_install",
686
453
  "package_create",
687
454
  "member_search",
688
455
  "role_search",
@@ -117,6 +117,7 @@ Analysis answers must include concrete numbers. When applicable, include percent
117
117
 
118
118
  - Read relation targets from `record_insert_schema_get` / `record_update_schema_get` relation metadata before preparing relation writes.
119
119
  - Member and department fields may be written with natural strings directly on `record_insert` / `record_update`; only fall back to `record_member_candidates` or `record_department_candidates` when the user wants explicit candidate browsing or the write returns ambiguity that needs confirmation.
120
+ - When candidate browsing must match a real update/write scope, pass `record_id`, `workflow_node_id`, and any pending `fields` context to the candidate tool; otherwise the candidate result is only a static applicant-node preview.
120
121
  - If explicit candidate browsing is needed for default-all member or department fields, prefer those field candidate tools instead of starting with `directory_*`.
121
122
 
122
123
  ## Code Block Path
@@ -143,11 +144,14 @@ Use `record_code_block_run` when the user wants to execute a form code-block fie
143
144
 
144
145
  ## Task Workflow Path
145
146
 
146
- `task_list -> task_get -> task_action_execute`
147
+ `task_list -> task_get -> task_save_only / task_action_execute`
147
148
 
148
149
  - Use `task_associated_report_detail_get` for associated view or report details.
149
150
  - Use `task_workflow_log_get` for full workflow log history.
150
151
  - Task actions operate on `app_key + record_id + workflow_node_id`, not `task_id`.
152
+ - Treat `task_action_execute` as the tool-level action enum surface; the current task's real actions are only the ones listed in `task_get.capabilities.available_actions`.
153
+ - Use `task_save_only` when the user wants to save editable field changes on the current node without advancing the workflow.
154
+ - `save_only` is exposed only when the backend current-node `editableQueIds` signal returns a non-empty result; MCP no longer infers `save_only` from local schema reconstruction.
151
155
 
152
156
  ## Time Handling
153
157