@josephyan/qingflow-cli 0.2.0-beta.58 → 0.2.0-beta.60
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.
- package/README.md +3 -2
- package/docs/local-agent-install.md +9 -0
- package/npm/bin/qingflow.mjs +1 -1
- package/npm/lib/runtime.mjs +156 -21
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/qingflow_mcp/builder_facade/service.py +670 -191
- package/src/qingflow_mcp/cli/commands/app.py +16 -16
- package/src/qingflow_mcp/cli/commands/auth.py +19 -16
- package/src/qingflow_mcp/cli/commands/builder.py +124 -162
- package/src/qingflow_mcp/cli/commands/common.py +21 -95
- package/src/qingflow_mcp/cli/commands/imports.py +42 -34
- package/src/qingflow_mcp/cli/commands/record.py +131 -133
- package/src/qingflow_mcp/cli/commands/task.py +43 -44
- package/src/qingflow_mcp/cli/commands/workspace.py +10 -10
- package/src/qingflow_mcp/cli/context.py +35 -32
- package/src/qingflow_mcp/cli/formatters.py +124 -121
- package/src/qingflow_mcp/cli/main.py +52 -17
- package/src/qingflow_mcp/server_app_builder.py +122 -190
- package/src/qingflow_mcp/server_app_user.py +63 -662
- package/src/qingflow_mcp/solution/executor.py +63 -4
- package/src/qingflow_mcp/tools/solution_tools.py +115 -3
- package/src/qingflow_mcp/ops/__init__.py +0 -3
- package/src/qingflow_mcp/ops/apps.py +0 -64
- package/src/qingflow_mcp/ops/auth.py +0 -121
- package/src/qingflow_mcp/ops/base.py +0 -290
- package/src/qingflow_mcp/ops/builder.py +0 -357
- package/src/qingflow_mcp/ops/context.py +0 -120
- package/src/qingflow_mcp/ops/directory.py +0 -171
- package/src/qingflow_mcp/ops/feedback.py +0 -49
- package/src/qingflow_mcp/ops/files.py +0 -78
- package/src/qingflow_mcp/ops/imports.py +0 -140
- package/src/qingflow_mcp/ops/records.py +0 -415
- package/src/qingflow_mcp/ops/tasks.py +0 -171
- package/src/qingflow_mcp/ops/workspace.py +0 -76
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
from typing import Any
|
|
5
|
-
|
|
6
|
-
from ..errors import QingflowApiError
|
|
7
|
-
from ..json_types import JSONObject
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
_COMMON_KEYS = {
|
|
11
|
-
"ok",
|
|
12
|
-
"status",
|
|
13
|
-
"message",
|
|
14
|
-
"error_code",
|
|
15
|
-
"details",
|
|
16
|
-
"warnings",
|
|
17
|
-
"verification",
|
|
18
|
-
"profile",
|
|
19
|
-
"ws_id",
|
|
20
|
-
"request_id",
|
|
21
|
-
"request_route",
|
|
22
|
-
"output_profile",
|
|
23
|
-
"recoverable",
|
|
24
|
-
"missing_fields",
|
|
25
|
-
"allowed_values",
|
|
26
|
-
"suggested_next_call",
|
|
27
|
-
"noop",
|
|
28
|
-
"compact",
|
|
29
|
-
"summary",
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
_INTERNAL_LEGACY_KEY = "__legacy__"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def success_result(
|
|
36
|
-
code: str,
|
|
37
|
-
message: str,
|
|
38
|
-
*,
|
|
39
|
-
data: Any = None,
|
|
40
|
-
warnings: list[Any] | None = None,
|
|
41
|
-
meta: JSONObject | None = None,
|
|
42
|
-
legacy: Any = None,
|
|
43
|
-
) -> JSONObject:
|
|
44
|
-
payload: JSONObject = {
|
|
45
|
-
"ok": True,
|
|
46
|
-
"code": code,
|
|
47
|
-
"message": message,
|
|
48
|
-
"data": data if data is not None else {},
|
|
49
|
-
"warnings": list(warnings or []),
|
|
50
|
-
"meta": dict(meta or {}),
|
|
51
|
-
}
|
|
52
|
-
if legacy is not None:
|
|
53
|
-
payload[_INTERNAL_LEGACY_KEY] = legacy
|
|
54
|
-
return payload
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def error_result(
|
|
58
|
-
code: str,
|
|
59
|
-
message: str,
|
|
60
|
-
*,
|
|
61
|
-
details: Any = None,
|
|
62
|
-
suggested_next: Any = None,
|
|
63
|
-
meta: JSONObject | None = None,
|
|
64
|
-
legacy: Any = None,
|
|
65
|
-
) -> JSONObject:
|
|
66
|
-
payload: JSONObject = {
|
|
67
|
-
"ok": False,
|
|
68
|
-
"code": code,
|
|
69
|
-
"message": message,
|
|
70
|
-
"details": details if details is not None else {},
|
|
71
|
-
"meta": dict(meta or {}),
|
|
72
|
-
}
|
|
73
|
-
if suggested_next is not None:
|
|
74
|
-
payload["suggested_next"] = suggested_next
|
|
75
|
-
if legacy is not None:
|
|
76
|
-
payload[_INTERNAL_LEGACY_KEY] = legacy
|
|
77
|
-
return payload
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def build_meta(raw: Any, *, extra: JSONObject | None = None) -> JSONObject:
|
|
81
|
-
meta: JSONObject = {}
|
|
82
|
-
if isinstance(raw, dict):
|
|
83
|
-
if raw.get("profile") is not None:
|
|
84
|
-
meta["profile"] = raw.get("profile")
|
|
85
|
-
if raw.get("ws_id") is not None:
|
|
86
|
-
meta["workspace_id"] = raw.get("ws_id")
|
|
87
|
-
if raw.get("request_id") is not None:
|
|
88
|
-
meta["request_id"] = raw.get("request_id")
|
|
89
|
-
if isinstance(raw.get("request_route"), dict):
|
|
90
|
-
meta["request_route"] = raw.get("request_route")
|
|
91
|
-
if isinstance(raw.get("verification"), dict) and raw.get("verification"):
|
|
92
|
-
meta["verification"] = raw.get("verification")
|
|
93
|
-
if extra:
|
|
94
|
-
meta.update(extra)
|
|
95
|
-
return meta
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def collect_warnings(raw: Any) -> list[Any]:
|
|
99
|
-
warnings: list[Any] = []
|
|
100
|
-
if isinstance(raw, dict):
|
|
101
|
-
if isinstance(raw.get("warnings"), list):
|
|
102
|
-
warnings.extend(raw["warnings"])
|
|
103
|
-
status = str(raw.get("status") or "").lower()
|
|
104
|
-
if status == "partial_success":
|
|
105
|
-
warnings.append(
|
|
106
|
-
{
|
|
107
|
-
"code": "PARTIAL_SUCCESS",
|
|
108
|
-
"message": str(raw.get("message") or "operation completed with warnings"),
|
|
109
|
-
}
|
|
110
|
-
)
|
|
111
|
-
return warnings
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def tool_payload(raw: Any) -> Any:
|
|
115
|
-
if not isinstance(raw, dict):
|
|
116
|
-
return raw
|
|
117
|
-
if "data" in raw:
|
|
118
|
-
return raw.get("data")
|
|
119
|
-
if "items" in raw:
|
|
120
|
-
return {
|
|
121
|
-
"items": raw.get("items") if isinstance(raw.get("items"), list) else [],
|
|
122
|
-
"count": raw.get("count"),
|
|
123
|
-
}
|
|
124
|
-
if "page" in raw:
|
|
125
|
-
page = raw.get("page")
|
|
126
|
-
if isinstance(page, dict):
|
|
127
|
-
return {
|
|
128
|
-
"items": page.get("list") if isinstance(page.get("list"), list) else [],
|
|
129
|
-
"page": page,
|
|
130
|
-
}
|
|
131
|
-
if "result" in raw:
|
|
132
|
-
return raw.get("result")
|
|
133
|
-
return {key: value for key, value in raw.items() if key not in _COMMON_KEYS}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
def is_failed_tool_result(raw: Any) -> bool:
|
|
137
|
-
if not isinstance(raw, dict):
|
|
138
|
-
return False
|
|
139
|
-
if raw.get("ok") is False:
|
|
140
|
-
return True
|
|
141
|
-
status = str(raw.get("status") or "").lower()
|
|
142
|
-
return status in {"failed", "blocked"}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
def tool_result_to_cli(
|
|
146
|
-
raw: Any,
|
|
147
|
-
*,
|
|
148
|
-
code: str,
|
|
149
|
-
message: str,
|
|
150
|
-
data: Any = None,
|
|
151
|
-
meta: JSONObject | None = None,
|
|
152
|
-
) -> JSONObject:
|
|
153
|
-
if is_failed_tool_result(raw):
|
|
154
|
-
payload = normalize_tool_error(raw)
|
|
155
|
-
payload["meta"] = build_meta(raw, extra=meta)
|
|
156
|
-
return payload
|
|
157
|
-
return success_result(
|
|
158
|
-
code,
|
|
159
|
-
message,
|
|
160
|
-
data=tool_payload(raw) if data is None else data,
|
|
161
|
-
warnings=collect_warnings(raw),
|
|
162
|
-
meta=build_meta(raw, extra=meta),
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def normalize_tool_error(raw: Any) -> JSONObject:
|
|
167
|
-
if isinstance(raw, dict):
|
|
168
|
-
details = raw.get("details")
|
|
169
|
-
if not isinstance(details, dict):
|
|
170
|
-
details = {}
|
|
171
|
-
if raw.get("backend_code") is not None:
|
|
172
|
-
details.setdefault("backend_code", raw.get("backend_code"))
|
|
173
|
-
if raw.get("request_id") is not None:
|
|
174
|
-
details.setdefault("request_id", raw.get("request_id"))
|
|
175
|
-
if raw.get("verification") not in (None, {}):
|
|
176
|
-
details.setdefault("verification", raw.get("verification"))
|
|
177
|
-
return error_result(
|
|
178
|
-
str(raw.get("error_code") or raw.get("code") or raw.get("category") or "OPERATION_FAILED"),
|
|
179
|
-
str(raw.get("message") or "operation failed"),
|
|
180
|
-
details=details,
|
|
181
|
-
suggested_next=raw.get("suggested_next_call"),
|
|
182
|
-
legacy=raw,
|
|
183
|
-
)
|
|
184
|
-
return error_result("OPERATION_FAILED", str(raw))
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def coerce_runtime_error(exc: RuntimeError) -> QingflowApiError:
|
|
188
|
-
raw = str(exc)
|
|
189
|
-
try:
|
|
190
|
-
payload = json.loads(raw)
|
|
191
|
-
except json.JSONDecodeError:
|
|
192
|
-
return QingflowApiError(category="runtime", message=raw)
|
|
193
|
-
if not isinstance(payload, dict):
|
|
194
|
-
return QingflowApiError(category="runtime", message=raw)
|
|
195
|
-
return QingflowApiError(
|
|
196
|
-
category=str(payload.get("category") or "runtime"),
|
|
197
|
-
message=str(payload.get("message") or raw),
|
|
198
|
-
backend_code=payload.get("backend_code"),
|
|
199
|
-
request_id=payload.get("request_id"),
|
|
200
|
-
details=payload.get("details") if isinstance(payload.get("details"), dict) else None,
|
|
201
|
-
)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
def normalize_exception(error: Exception) -> JSONObject:
|
|
205
|
-
if isinstance(error, RuntimeError):
|
|
206
|
-
api_error = coerce_runtime_error(error)
|
|
207
|
-
elif isinstance(error, QingflowApiError):
|
|
208
|
-
api_error = error
|
|
209
|
-
else:
|
|
210
|
-
return error_result("RUNTIME_ERROR", str(error))
|
|
211
|
-
|
|
212
|
-
details = dict(api_error.details or {})
|
|
213
|
-
if api_error.backend_code is not None:
|
|
214
|
-
details.setdefault("backend_code", api_error.backend_code)
|
|
215
|
-
if api_error.request_id is not None:
|
|
216
|
-
details.setdefault("request_id", api_error.request_id)
|
|
217
|
-
code = str(details.pop("error_code", None) or api_error.category or "OPERATION_FAILED").upper()
|
|
218
|
-
if code == "CONFIG":
|
|
219
|
-
code = "INVALID_ARGUMENT"
|
|
220
|
-
elif code == "AUTH":
|
|
221
|
-
code = "AUTH_REQUIRED"
|
|
222
|
-
elif code == "WORKSPACE":
|
|
223
|
-
code = "WORKSPACE_NOT_SELECTED"
|
|
224
|
-
legacy_payload = None
|
|
225
|
-
if isinstance(error, RuntimeError):
|
|
226
|
-
raw = str(error)
|
|
227
|
-
try:
|
|
228
|
-
parsed = json.loads(raw)
|
|
229
|
-
except json.JSONDecodeError:
|
|
230
|
-
parsed = None
|
|
231
|
-
if isinstance(parsed, dict):
|
|
232
|
-
legacy_payload = parsed
|
|
233
|
-
return error_result(code, api_error.message, details=details, legacy=legacy_payload)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
def public_result(payload: Any) -> Any:
|
|
237
|
-
if isinstance(payload, dict):
|
|
238
|
-
return {
|
|
239
|
-
key: public_result(value)
|
|
240
|
-
for key, value in payload.items()
|
|
241
|
-
if key != _INTERNAL_LEGACY_KEY
|
|
242
|
-
}
|
|
243
|
-
if isinstance(payload, list):
|
|
244
|
-
return [public_result(item) for item in payload]
|
|
245
|
-
return payload
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
def mcp_result_from_operation(result: Any) -> Any:
|
|
249
|
-
if not isinstance(result, dict):
|
|
250
|
-
return result
|
|
251
|
-
legacy = result.get(_INTERNAL_LEGACY_KEY)
|
|
252
|
-
if isinstance(legacy, dict):
|
|
253
|
-
return legacy
|
|
254
|
-
meta = result.get("meta") if isinstance(result.get("meta"), dict) else {}
|
|
255
|
-
if result.get("ok") is False:
|
|
256
|
-
payload: JSONObject = {
|
|
257
|
-
"ok": False,
|
|
258
|
-
"status": "failed",
|
|
259
|
-
"error_code": result.get("code") or "OPERATION_FAILED",
|
|
260
|
-
"message": result.get("message") or "operation failed",
|
|
261
|
-
"details": result.get("details") if isinstance(result.get("details"), dict) else {},
|
|
262
|
-
"warnings": result.get("warnings") if isinstance(result.get("warnings"), list) else [],
|
|
263
|
-
}
|
|
264
|
-
if isinstance(meta.get("request_route"), dict):
|
|
265
|
-
payload["request_route"] = meta["request_route"]
|
|
266
|
-
if isinstance(meta.get("verification"), dict):
|
|
267
|
-
payload["verification"] = meta["verification"]
|
|
268
|
-
if meta.get("profile") is not None:
|
|
269
|
-
payload["profile"] = meta.get("profile")
|
|
270
|
-
if meta.get("workspace_id") is not None:
|
|
271
|
-
payload["ws_id"] = meta.get("workspace_id")
|
|
272
|
-
if result.get("suggested_next") is not None:
|
|
273
|
-
payload["suggested_next_call"] = result.get("suggested_next")
|
|
274
|
-
return payload
|
|
275
|
-
payload = {
|
|
276
|
-
"ok": True,
|
|
277
|
-
"status": "success",
|
|
278
|
-
"message": result.get("message") or "ok",
|
|
279
|
-
"data": result.get("data"),
|
|
280
|
-
"warnings": result.get("warnings") if isinstance(result.get("warnings"), list) else [],
|
|
281
|
-
}
|
|
282
|
-
if isinstance(meta.get("request_route"), dict):
|
|
283
|
-
payload["request_route"] = meta["request_route"]
|
|
284
|
-
if isinstance(meta.get("verification"), dict):
|
|
285
|
-
payload["verification"] = meta["verification"]
|
|
286
|
-
if meta.get("profile") is not None:
|
|
287
|
-
payload["profile"] = meta.get("profile")
|
|
288
|
-
if meta.get("workspace_id") is not None:
|
|
289
|
-
payload["ws_id"] = meta.get("workspace_id")
|
|
290
|
-
return payload
|
|
@@ -1,357 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import Any
|
|
4
|
-
|
|
5
|
-
from .base import normalize_tool_error, success_result, tool_payload
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class BuilderOperations:
|
|
9
|
-
def __init__(self, tools: Any) -> None:
|
|
10
|
-
self._tools = tools
|
|
11
|
-
|
|
12
|
-
def package_list(self, *, profile: str, trial_status: str) -> dict:
|
|
13
|
-
return self._call("PACKAGES_READY", "已读取应用包列表", self._tools.builder.package_list(profile=profile, trial_status=trial_status))
|
|
14
|
-
|
|
15
|
-
def package_resolve(self, *, profile: str, package_name: str) -> dict:
|
|
16
|
-
return self._call("PACKAGE_RESOLVED", "已解析应用包", self._tools.builder.package_resolve(profile=profile, package_name=package_name))
|
|
17
|
-
|
|
18
|
-
def builder_tool_contract(self, *, tool_name: str) -> dict:
|
|
19
|
-
return self._call("BUILDER_TOOL_CONTRACT_READY", "已读取工具契约", self._tools.builder.builder_tool_contract(tool_name=tool_name))
|
|
20
|
-
|
|
21
|
-
def package_create(self, *, profile: str, package_name: str) -> dict:
|
|
22
|
-
return self._call("PACKAGE_CREATED", "已创建应用包", self._tools.builder.package_create(profile=profile, package_name=package_name))
|
|
23
|
-
|
|
24
|
-
def member_search(
|
|
25
|
-
self,
|
|
26
|
-
*,
|
|
27
|
-
profile: str,
|
|
28
|
-
query: str,
|
|
29
|
-
page_num: int,
|
|
30
|
-
page_size: int,
|
|
31
|
-
contain_disable: bool,
|
|
32
|
-
) -> dict:
|
|
33
|
-
return self._call(
|
|
34
|
-
"MEMBERS_READY",
|
|
35
|
-
"已读取成员候选",
|
|
36
|
-
self._tools.builder.member_search(
|
|
37
|
-
profile=profile,
|
|
38
|
-
query=query,
|
|
39
|
-
page_num=page_num,
|
|
40
|
-
page_size=page_size,
|
|
41
|
-
contain_disable=contain_disable,
|
|
42
|
-
),
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
def role_search(self, *, profile: str, keyword: str, page_num: int, page_size: int) -> dict:
|
|
46
|
-
return self._call(
|
|
47
|
-
"ROLES_READY",
|
|
48
|
-
"已读取角色候选",
|
|
49
|
-
self._tools.builder.role_search(profile=profile, keyword=keyword, page_num=page_num, page_size=page_size),
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
def role_create(
|
|
53
|
-
self,
|
|
54
|
-
*,
|
|
55
|
-
profile: str,
|
|
56
|
-
role_name: str,
|
|
57
|
-
member_uids: list[int],
|
|
58
|
-
member_emails: list[str],
|
|
59
|
-
member_names: list[str],
|
|
60
|
-
role_icon: str,
|
|
61
|
-
) -> dict:
|
|
62
|
-
return self._call(
|
|
63
|
-
"ROLE_CREATED",
|
|
64
|
-
"已创建角色",
|
|
65
|
-
self._tools.builder.role_create(
|
|
66
|
-
profile=profile,
|
|
67
|
-
role_name=role_name,
|
|
68
|
-
member_uids=member_uids,
|
|
69
|
-
member_emails=member_emails,
|
|
70
|
-
member_names=member_names,
|
|
71
|
-
role_icon=role_icon,
|
|
72
|
-
),
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
def package_attach_app(self, *, profile: str, tag_id: int, app_key: str, app_title: str) -> dict:
|
|
76
|
-
return self._call(
|
|
77
|
-
"PACKAGE_APP_ATTACHED",
|
|
78
|
-
"已挂载应用到应用包",
|
|
79
|
-
self._tools.builder.package_attach_app(profile=profile, tag_id=tag_id, app_key=app_key, app_title=app_title),
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
def release_edit_lock_if_mine(
|
|
83
|
-
self,
|
|
84
|
-
*,
|
|
85
|
-
profile: str,
|
|
86
|
-
app_key: str,
|
|
87
|
-
lock_owner_email: str,
|
|
88
|
-
lock_owner_name: str,
|
|
89
|
-
) -> dict:
|
|
90
|
-
return self._call(
|
|
91
|
-
"APP_EDIT_LOCK_RELEASED",
|
|
92
|
-
"已释放编辑锁",
|
|
93
|
-
self._tools.builder.app_release_edit_lock_if_mine(
|
|
94
|
-
profile=profile,
|
|
95
|
-
app_key=app_key,
|
|
96
|
-
lock_owner_email=lock_owner_email,
|
|
97
|
-
lock_owner_name=lock_owner_name,
|
|
98
|
-
),
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
def app_resolve(self, *, profile: str, app_key: str, app_name: str, package_tag_id: int | None) -> dict:
|
|
102
|
-
return self._call(
|
|
103
|
-
"APP_RESOLVED",
|
|
104
|
-
"已解析应用",
|
|
105
|
-
self._tools.builder.app_resolve(
|
|
106
|
-
profile=profile,
|
|
107
|
-
app_key=app_key,
|
|
108
|
-
app_name=app_name,
|
|
109
|
-
package_tag_id=package_tag_id,
|
|
110
|
-
),
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
def app_show(self, *, profile: str, app_key: str) -> dict:
|
|
114
|
-
return self._call("APP_SUMMARY_READY", "已读取应用摘要", self._tools.builder.app_read_summary(profile=profile, app_key=app_key))
|
|
115
|
-
|
|
116
|
-
def fields_show(self, *, profile: str, app_key: str) -> dict:
|
|
117
|
-
return self._call("FIELDS_READY", "已读取字段摘要", self._tools.builder.app_read_fields(profile=profile, app_key=app_key))
|
|
118
|
-
|
|
119
|
-
def layout_show(self, *, profile: str, app_key: str) -> dict:
|
|
120
|
-
return self._call("LAYOUT_READY", "已读取布局摘要", self._tools.builder.app_read_layout_summary(profile=profile, app_key=app_key))
|
|
121
|
-
|
|
122
|
-
def views_show(self, *, profile: str, app_key: str) -> dict:
|
|
123
|
-
return self._call("VIEWS_READY", "已读取视图摘要", self._tools.builder.app_read_views_summary(profile=profile, app_key=app_key))
|
|
124
|
-
|
|
125
|
-
def flow_show(self, *, profile: str, app_key: str) -> dict:
|
|
126
|
-
return self._call("FLOW_READY", "已读取流程摘要", self._tools.builder.app_read_flow_summary(profile=profile, app_key=app_key))
|
|
127
|
-
|
|
128
|
-
def charts_show(self, *, profile: str, app_key: str) -> dict:
|
|
129
|
-
return self._call("CHARTS_READY", "已读取报表摘要", self._tools.builder.app_read_charts_summary(profile=profile, app_key=app_key))
|
|
130
|
-
|
|
131
|
-
def portal_show(self, *, profile: str, dash_key: str, being_draft: bool) -> dict:
|
|
132
|
-
return self._call(
|
|
133
|
-
"PORTAL_READY",
|
|
134
|
-
"已读取门户摘要",
|
|
135
|
-
self._tools.builder.portal_read_summary(profile=profile, dash_key=dash_key, being_draft=being_draft),
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
def fields_apply(
|
|
139
|
-
self,
|
|
140
|
-
*,
|
|
141
|
-
profile: str,
|
|
142
|
-
app_key: str,
|
|
143
|
-
package_tag_id: int | None,
|
|
144
|
-
app_name: str,
|
|
145
|
-
app_title: str,
|
|
146
|
-
create_if_missing: bool,
|
|
147
|
-
publish: bool,
|
|
148
|
-
add_fields: list[Any],
|
|
149
|
-
update_fields: list[Any],
|
|
150
|
-
remove_fields: list[Any],
|
|
151
|
-
) -> dict:
|
|
152
|
-
return self._call(
|
|
153
|
-
"FIELDS_APPLIED",
|
|
154
|
-
"已执行字段变更",
|
|
155
|
-
self._tools.builder.app_schema_apply(
|
|
156
|
-
profile=profile,
|
|
157
|
-
app_key=app_key,
|
|
158
|
-
package_tag_id=package_tag_id,
|
|
159
|
-
app_name=app_name,
|
|
160
|
-
app_title=app_title,
|
|
161
|
-
create_if_missing=create_if_missing,
|
|
162
|
-
publish=publish,
|
|
163
|
-
add_fields=[_normalize_field_spec(item) for item in add_fields],
|
|
164
|
-
update_fields=[_normalize_field_update(item) for item in update_fields],
|
|
165
|
-
remove_fields=[_normalize_field_selector(item) for item in remove_fields],
|
|
166
|
-
),
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
def layout_apply(
|
|
170
|
-
self,
|
|
171
|
-
*,
|
|
172
|
-
profile: str,
|
|
173
|
-
app_key: str,
|
|
174
|
-
mode: str,
|
|
175
|
-
publish: bool,
|
|
176
|
-
sections: list[Any],
|
|
177
|
-
) -> dict:
|
|
178
|
-
return self._call(
|
|
179
|
-
"LAYOUT_APPLIED",
|
|
180
|
-
"已执行布局变更",
|
|
181
|
-
self._tools.builder.app_layout_apply(
|
|
182
|
-
profile=profile,
|
|
183
|
-
app_key=app_key,
|
|
184
|
-
mode=mode,
|
|
185
|
-
publish=publish,
|
|
186
|
-
sections=sections,
|
|
187
|
-
),
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
def flow_apply(
|
|
191
|
-
self,
|
|
192
|
-
*,
|
|
193
|
-
profile: str,
|
|
194
|
-
app_key: str,
|
|
195
|
-
mode: str,
|
|
196
|
-
publish: bool,
|
|
197
|
-
nodes: list[Any],
|
|
198
|
-
transitions: list[Any],
|
|
199
|
-
) -> dict:
|
|
200
|
-
return self._call(
|
|
201
|
-
"FLOW_APPLIED",
|
|
202
|
-
"已执行流程变更",
|
|
203
|
-
self._tools.builder.app_flow_apply(
|
|
204
|
-
profile=profile,
|
|
205
|
-
app_key=app_key,
|
|
206
|
-
mode=mode,
|
|
207
|
-
publish=publish,
|
|
208
|
-
nodes=nodes,
|
|
209
|
-
transitions=transitions,
|
|
210
|
-
),
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
def views_apply(
|
|
214
|
-
self,
|
|
215
|
-
*,
|
|
216
|
-
profile: str,
|
|
217
|
-
app_key: str,
|
|
218
|
-
publish: bool,
|
|
219
|
-
upsert_views: list[Any],
|
|
220
|
-
remove_views: list[Any],
|
|
221
|
-
) -> dict:
|
|
222
|
-
return self._call(
|
|
223
|
-
"VIEWS_APPLIED",
|
|
224
|
-
"已执行视图变更",
|
|
225
|
-
self._tools.builder.app_views_apply(
|
|
226
|
-
profile=profile,
|
|
227
|
-
app_key=app_key,
|
|
228
|
-
publish=publish,
|
|
229
|
-
upsert_views=upsert_views,
|
|
230
|
-
remove_views=remove_views,
|
|
231
|
-
),
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
def charts_apply(
|
|
235
|
-
self,
|
|
236
|
-
*,
|
|
237
|
-
profile: str,
|
|
238
|
-
app_key: str,
|
|
239
|
-
upsert_charts: list[Any],
|
|
240
|
-
remove_chart_ids: list[Any],
|
|
241
|
-
reorder_chart_ids: list[Any],
|
|
242
|
-
) -> dict:
|
|
243
|
-
return self._call(
|
|
244
|
-
"CHARTS_APPLIED",
|
|
245
|
-
"已执行报表变更",
|
|
246
|
-
self._tools.builder.app_charts_apply(
|
|
247
|
-
profile=profile,
|
|
248
|
-
app_key=app_key,
|
|
249
|
-
upsert_charts=upsert_charts,
|
|
250
|
-
remove_chart_ids=remove_chart_ids,
|
|
251
|
-
reorder_chart_ids=reorder_chart_ids,
|
|
252
|
-
),
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
def portal_apply(
|
|
256
|
-
self,
|
|
257
|
-
*,
|
|
258
|
-
profile: str,
|
|
259
|
-
dash_key: str,
|
|
260
|
-
dash_name: str,
|
|
261
|
-
package_tag_id: int | None,
|
|
262
|
-
publish: bool,
|
|
263
|
-
sections: list[Any],
|
|
264
|
-
auth: dict | None,
|
|
265
|
-
icon: str | None,
|
|
266
|
-
color: str | None,
|
|
267
|
-
hide_copyright: bool | None,
|
|
268
|
-
dash_global_config: dict | None,
|
|
269
|
-
config: dict | None,
|
|
270
|
-
) -> dict:
|
|
271
|
-
return self._call(
|
|
272
|
-
"PORTAL_APPLIED",
|
|
273
|
-
"已执行门户变更",
|
|
274
|
-
self._tools.builder.portal_apply(
|
|
275
|
-
profile=profile,
|
|
276
|
-
dash_key=dash_key,
|
|
277
|
-
dash_name=dash_name,
|
|
278
|
-
package_tag_id=package_tag_id,
|
|
279
|
-
publish=publish,
|
|
280
|
-
sections=sections,
|
|
281
|
-
auth=auth,
|
|
282
|
-
icon=icon,
|
|
283
|
-
color=color,
|
|
284
|
-
hide_copyright=hide_copyright,
|
|
285
|
-
dash_global_config=dash_global_config,
|
|
286
|
-
config=config,
|
|
287
|
-
),
|
|
288
|
-
)
|
|
289
|
-
|
|
290
|
-
def publish_verify(self, *, profile: str, app_key: str, expected_package_tag_id: int | None) -> dict:
|
|
291
|
-
return self._call(
|
|
292
|
-
"PUBLISH_VERIFIED",
|
|
293
|
-
"已完成发布校验",
|
|
294
|
-
self._tools.builder.app_publish_verify(
|
|
295
|
-
profile=profile,
|
|
296
|
-
app_key=app_key,
|
|
297
|
-
expected_package_tag_id=expected_package_tag_id,
|
|
298
|
-
),
|
|
299
|
-
)
|
|
300
|
-
|
|
301
|
-
def _call(self, code: str, message: str, raw: Any) -> dict:
|
|
302
|
-
if isinstance(raw, dict) and (raw.get("ok") is False or str(raw.get("status") or "").lower() in {"failed", "blocked"}):
|
|
303
|
-
return normalize_tool_error(raw)
|
|
304
|
-
warnings = raw.get("warnings") if isinstance(raw, dict) and isinstance(raw.get("warnings"), list) else []
|
|
305
|
-
meta = {}
|
|
306
|
-
if isinstance(raw, dict):
|
|
307
|
-
if raw.get("profile") is not None:
|
|
308
|
-
meta["profile"] = raw.get("profile")
|
|
309
|
-
if raw.get("request_id") is not None:
|
|
310
|
-
meta["request_id"] = raw.get("request_id")
|
|
311
|
-
if raw.get("request_route") is not None:
|
|
312
|
-
meta["request_route"] = raw.get("request_route")
|
|
313
|
-
if raw.get("verification") not in (None, {}):
|
|
314
|
-
meta["verification"] = raw.get("verification")
|
|
315
|
-
data = tool_payload(raw)
|
|
316
|
-
if isinstance(data, dict):
|
|
317
|
-
normalized_args = data.pop("normalized_args", None)
|
|
318
|
-
verified = data.pop("verified", None)
|
|
319
|
-
if normalized_args is not None:
|
|
320
|
-
meta["normalized_args"] = normalized_args
|
|
321
|
-
if verified is not None:
|
|
322
|
-
meta["verified"] = verified
|
|
323
|
-
return success_result(code, message, data=data, warnings=warnings, meta=meta, legacy=raw)
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
def _normalize_field_spec(value: Any) -> Any:
|
|
327
|
-
if not isinstance(value, dict):
|
|
328
|
-
return value
|
|
329
|
-
normalized = dict(value)
|
|
330
|
-
if "name" not in normalized and isinstance(normalized.get("field_name"), str):
|
|
331
|
-
normalized["name"] = normalized["field_name"]
|
|
332
|
-
if "type" not in normalized and isinstance(normalized.get("field_type"), str):
|
|
333
|
-
normalized["type"] = normalized["field_type"]
|
|
334
|
-
normalized.pop("field_name", None)
|
|
335
|
-
normalized.pop("field_type", None)
|
|
336
|
-
return normalized
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
def _normalize_field_selector(value: Any) -> Any:
|
|
340
|
-
if not isinstance(value, dict):
|
|
341
|
-
return value
|
|
342
|
-
normalized = dict(value)
|
|
343
|
-
if "name" not in normalized and isinstance(normalized.get("field_name"), str):
|
|
344
|
-
normalized["name"] = normalized["field_name"]
|
|
345
|
-
normalized.pop("field_name", None)
|
|
346
|
-
return normalized
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
def _normalize_field_update(value: Any) -> Any:
|
|
350
|
-
if not isinstance(value, dict):
|
|
351
|
-
return value
|
|
352
|
-
normalized = dict(value)
|
|
353
|
-
if isinstance(normalized.get("selector"), dict):
|
|
354
|
-
normalized["selector"] = _normalize_field_selector(normalized["selector"])
|
|
355
|
-
if isinstance(normalized.get("set"), dict):
|
|
356
|
-
normalized["set"] = _normalize_field_spec(normalized["set"])
|
|
357
|
-
return normalized
|