@josephyan/qingflow-cli 0.2.0-beta.69 → 0.2.0-beta.71
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 +2 -2
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/qingflow_mcp/backend_client.py +0 -1
- package/src/qingflow_mcp/builder_facade/models.py +34 -0
- package/src/qingflow_mcp/builder_facade/service.py +372 -17
- package/src/qingflow_mcp/cli/commands/builder.py +248 -1
- package/src/qingflow_mcp/cli/commands/common.py +15 -0
- package/src/qingflow_mcp/cli/commands/imports.py +12 -2
- package/src/qingflow_mcp/cli/commands/record.py +132 -32
- package/src/qingflow_mcp/cli/commands/workspace.py +1 -1
- package/src/qingflow_mcp/cli/formatters.py +52 -2
- package/src/qingflow_mcp/cli/main.py +7 -5
- package/src/qingflow_mcp/response_trim.py +668 -0
- package/src/qingflow_mcp/server_app_builder.py +136 -8
- package/src/qingflow_mcp/server_app_user.py +55 -11
- package/src/qingflow_mcp/tools/ai_builder_tools.py +270 -5
- package/src/qingflow_mcp/tools/app_tools.py +29 -0
- package/src/qingflow_mcp/tools/auth_tools.py +259 -1
- package/src/qingflow_mcp/tools/import_tools.py +59 -7
- package/src/qingflow_mcp/tools/qingbi_report_tools.py +75 -7
- package/src/qingflow_mcp/tools/record_tools.py +6 -12
- package/src/qingflow_mcp/tools/workspace_tools.py +124 -7
|
@@ -139,21 +139,28 @@ class WorkspaceTools(ToolBase):
|
|
|
139
139
|
qf_version=workspace_qf_version,
|
|
140
140
|
qf_version_source="workspace_system_version",
|
|
141
141
|
)
|
|
142
|
+
active_context = BackendRequestContext(
|
|
143
|
+
base_url=session_profile.base_url,
|
|
144
|
+
token=context.token,
|
|
145
|
+
ws_id=session_profile.selected_ws_id,
|
|
146
|
+
qf_version=session_profile.qf_version,
|
|
147
|
+
qf_version_source=session_profile.qf_version_source,
|
|
148
|
+
)
|
|
149
|
+
workspace_version = self._workspace_version_summary(
|
|
150
|
+
self._fetch_workspace_account_info(active_context),
|
|
151
|
+
workspace_base_info=self._fetch_workspace_base_info(active_context),
|
|
152
|
+
workspace_detail=result,
|
|
153
|
+
)
|
|
142
154
|
return {
|
|
143
155
|
"profile": profile,
|
|
144
156
|
"selected_ws_id": session_profile.selected_ws_id,
|
|
145
157
|
"selected_ws_name": session_profile.selected_ws_name,
|
|
146
158
|
"workspace": result,
|
|
159
|
+
"workspace_version": workspace_version,
|
|
147
160
|
"qf_version": session_profile.qf_version,
|
|
148
161
|
"qf_version_source": session_profile.qf_version_source,
|
|
149
162
|
"request_route": self.backend.describe_route(
|
|
150
|
-
|
|
151
|
-
base_url=session_profile.base_url,
|
|
152
|
-
token=context.token,
|
|
153
|
-
ws_id=session_profile.selected_ws_id,
|
|
154
|
-
qf_version=session_profile.qf_version,
|
|
155
|
-
qf_version_source=session_profile.qf_version_source,
|
|
156
|
-
)
|
|
163
|
+
active_context
|
|
157
164
|
),
|
|
158
165
|
}
|
|
159
166
|
|
|
@@ -189,6 +196,116 @@ class WorkspaceTools(ToolBase):
|
|
|
189
196
|
normalized = str(value).strip()
|
|
190
197
|
return normalized or None
|
|
191
198
|
|
|
199
|
+
def _fetch_workspace_base_info(self, context: BackendRequestContext) -> dict[str, Any] | None:
|
|
200
|
+
try:
|
|
201
|
+
payload = self.backend.request("GET", context, "/ws/baseInfo")
|
|
202
|
+
except QingflowApiError:
|
|
203
|
+
return None
|
|
204
|
+
return payload if isinstance(payload, dict) else None
|
|
205
|
+
|
|
206
|
+
def _fetch_workspace_account_info(self, context: BackendRequestContext) -> dict[str, Any] | None:
|
|
207
|
+
try:
|
|
208
|
+
payload = self.backend.request("GET", context, "/ws/account")
|
|
209
|
+
except QingflowApiError:
|
|
210
|
+
return None
|
|
211
|
+
return payload if isinstance(payload, dict) else None
|
|
212
|
+
|
|
213
|
+
def _workspace_version_summary(
|
|
214
|
+
self,
|
|
215
|
+
payload: Any,
|
|
216
|
+
*,
|
|
217
|
+
workspace_base_info: Any,
|
|
218
|
+
workspace_detail: Any,
|
|
219
|
+
) -> dict[str, Any]:
|
|
220
|
+
account_info = payload if isinstance(payload, dict) else {}
|
|
221
|
+
base_info = workspace_base_info if isinstance(workspace_base_info, dict) else {}
|
|
222
|
+
detail_info = workspace_detail if isinstance(workspace_detail, dict) else {}
|
|
223
|
+
level_code = self._first_present_int(
|
|
224
|
+
account_info.get("accountLevel"),
|
|
225
|
+
base_info.get("accountLevel"),
|
|
226
|
+
detail_info.get("accountLevel"),
|
|
227
|
+
)
|
|
228
|
+
level_name = self._account_level_name(level_code)
|
|
229
|
+
return {
|
|
230
|
+
"level_code": level_code,
|
|
231
|
+
"level_name": level_name,
|
|
232
|
+
"display_name": self._account_level_display_name(level_name),
|
|
233
|
+
"being_trial": self._first_present_bool(
|
|
234
|
+
account_info.get("trial"),
|
|
235
|
+
base_info.get("trial"),
|
|
236
|
+
detail_info.get("trial"),
|
|
237
|
+
),
|
|
238
|
+
"expire_date": self._first_present_value(
|
|
239
|
+
account_info.get("expireDate"),
|
|
240
|
+
base_info.get("expireDate"),
|
|
241
|
+
detail_info.get("expireDate"),
|
|
242
|
+
),
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
def _account_level_name(self, level_code: int | None) -> str | None:
|
|
246
|
+
mapping = {
|
|
247
|
+
0: "FREE",
|
|
248
|
+
10: "AIR",
|
|
249
|
+
20: "BASIC",
|
|
250
|
+
30: "TEAM",
|
|
251
|
+
35: "PROFESSIONAL",
|
|
252
|
+
40: "ENTERPRISE",
|
|
253
|
+
}
|
|
254
|
+
return mapping.get(level_code)
|
|
255
|
+
|
|
256
|
+
def _account_level_display_name(self, level_name: str | None) -> str | None:
|
|
257
|
+
mapping = {
|
|
258
|
+
"FREE": "免费版",
|
|
259
|
+
"AIR": "Air版",
|
|
260
|
+
"BASIC": "Pro版",
|
|
261
|
+
"TEAM": "团队版",
|
|
262
|
+
"PROFESSIONAL": "专业版",
|
|
263
|
+
"ENTERPRISE": "企业版",
|
|
264
|
+
}
|
|
265
|
+
return mapping.get(level_name)
|
|
266
|
+
|
|
267
|
+
def _coerce_int(self, value: Any) -> int | None:
|
|
268
|
+
if isinstance(value, bool) or value is None:
|
|
269
|
+
return None
|
|
270
|
+
if isinstance(value, int):
|
|
271
|
+
return value
|
|
272
|
+
try:
|
|
273
|
+
return int(str(value).strip())
|
|
274
|
+
except (TypeError, ValueError):
|
|
275
|
+
return None
|
|
276
|
+
|
|
277
|
+
def _coerce_bool(self, value: Any) -> bool | None:
|
|
278
|
+
if isinstance(value, bool):
|
|
279
|
+
return value
|
|
280
|
+
if value is None:
|
|
281
|
+
return None
|
|
282
|
+
normalized = str(value).strip().lower()
|
|
283
|
+
if normalized in {"true", "1"}:
|
|
284
|
+
return True
|
|
285
|
+
if normalized in {"false", "0"}:
|
|
286
|
+
return False
|
|
287
|
+
return None
|
|
288
|
+
|
|
289
|
+
def _first_present_int(self, *values: Any) -> int | None:
|
|
290
|
+
for value in values:
|
|
291
|
+
coerced = self._coerce_int(value)
|
|
292
|
+
if coerced is not None:
|
|
293
|
+
return coerced
|
|
294
|
+
return None
|
|
295
|
+
|
|
296
|
+
def _first_present_bool(self, *values: Any) -> bool | None:
|
|
297
|
+
for value in values:
|
|
298
|
+
coerced = self._coerce_bool(value)
|
|
299
|
+
if coerced is not None:
|
|
300
|
+
return coerced
|
|
301
|
+
return None
|
|
302
|
+
|
|
303
|
+
def _first_present_value(self, *values: Any) -> Any:
|
|
304
|
+
for value in values:
|
|
305
|
+
if value is not None:
|
|
306
|
+
return value
|
|
307
|
+
return None
|
|
308
|
+
|
|
192
309
|
def workspace_set_plugin_status(
|
|
193
310
|
self,
|
|
194
311
|
*,
|