@josephyan/qingflow-cli 0.2.0-beta.984 → 0.2.0-beta.986
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/docs/local-agent-install.md +70 -11
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/builder_facade/service.py +47 -21
- package/src/qingflow_mcp/cli/commands/auth.py +14 -43
- package/src/qingflow_mcp/cli/commands/task.py +4 -1
- package/src/qingflow_mcp/cli/commands/workspace.py +0 -8
- package/src/qingflow_mcp/cli/formatters.py +0 -21
- package/src/qingflow_mcp/config.py +39 -0
- package/src/qingflow_mcp/errors.py +2 -2
- package/src/qingflow_mcp/public_surface.py +2 -6
- package/src/qingflow_mcp/response_trim.py +1 -8
- package/src/qingflow_mcp/server.py +1 -1
- package/src/qingflow_mcp/server_app_builder.py +4 -28
- package/src/qingflow_mcp/server_app_user.py +4 -28
- package/src/qingflow_mcp/session_store.py +31 -5
- package/src/qingflow_mcp/tools/ai_builder_tools.py +117 -1
- package/src/qingflow_mcp/tools/app_tools.py +51 -1
- package/src/qingflow_mcp/tools/approval_tools.py +82 -1
- package/src/qingflow_mcp/tools/auth_tools.py +258 -288
- package/src/qingflow_mcp/tools/base.py +204 -4
- package/src/qingflow_mcp/tools/code_block_tools.py +21 -0
- package/src/qingflow_mcp/tools/custom_button_tools.py +24 -1
- package/src/qingflow_mcp/tools/directory_tools.py +28 -1
- package/src/qingflow_mcp/tools/feedback_tools.py +8 -0
- package/src/qingflow_mcp/tools/file_tools.py +25 -1
- package/src/qingflow_mcp/tools/import_tools.py +40 -1
- package/src/qingflow_mcp/tools/navigation_tools.py +34 -1
- package/src/qingflow_mcp/tools/package_tools.py +37 -1
- package/src/qingflow_mcp/tools/portal_tools.py +28 -1
- package/src/qingflow_mcp/tools/qingbi_report_tools.py +38 -1
- package/src/qingflow_mcp/tools/record_tools.py +255 -2
- package/src/qingflow_mcp/tools/repository_dev_tools.py +21 -2
- package/src/qingflow_mcp/tools/resource_read_tools.py +23 -1
- package/src/qingflow_mcp/tools/role_tools.py +19 -1
- package/src/qingflow_mcp/tools/solution_tools.py +56 -1
- package/src/qingflow_mcp/tools/task_context_tools.py +205 -6
- package/src/qingflow_mcp/tools/task_tools.py +49 -3
- package/src/qingflow_mcp/tools/view_tools.py +56 -1
- package/src/qingflow_mcp/tools/workflow_tools.py +65 -1
- package/src/qingflow_mcp/tools/workspace_tools.py +14 -225
|
@@ -10,11 +10,21 @@ from ..config import DEFAULT_PROFILE
|
|
|
10
10
|
from ..errors import QingflowApiError, raise_tool_error
|
|
11
11
|
from ..json_types import JSONObject
|
|
12
12
|
from ..list_type_labels import SYSTEM_VIEW_DEFINITIONS, get_app_publish_status_label
|
|
13
|
-
from .base import ToolBase
|
|
13
|
+
from .base import ToolBase, tool_cn_name
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class AppTools(ToolBase):
|
|
17
|
+
"""应用工具(中文名:应用与表单管理)。
|
|
18
|
+
|
|
19
|
+
类型:应用元数据与配置工具。
|
|
20
|
+
主要职责:
|
|
21
|
+
1. 查询应用列表、搜索应用、读取应用详情;
|
|
22
|
+
2. 读取与更新应用基础配置、表单结构与发布状态;
|
|
23
|
+
3. 提供应用创建、删除、发布等管理能力。
|
|
24
|
+
"""
|
|
25
|
+
|
|
17
26
|
def register(self, mcp: FastMCP) -> None:
|
|
27
|
+
"""注册当前工具到 MCP 服务。"""
|
|
18
28
|
@mcp.tool()
|
|
19
29
|
def app_list(profile: str = DEFAULT_PROFILE, ship_auth: bool = False) -> JSONObject:
|
|
20
30
|
return self.app_list(profile=profile, ship_auth=ship_auth)
|
|
@@ -79,6 +89,7 @@ class AppTools(ToolBase):
|
|
|
79
89
|
) -> JSONObject:
|
|
80
90
|
return self.app_publish(profile=profile, app_key=app_key, payload=payload or {})
|
|
81
91
|
|
|
92
|
+
@tool_cn_name("应用列表")
|
|
82
93
|
def app_list(self, *, profile: str, ship_auth: bool = False) -> JSONObject:
|
|
83
94
|
"""List current-user visible apps in the selected workspace."""
|
|
84
95
|
def runner(session_profile, context):
|
|
@@ -97,6 +108,7 @@ class AppTools(ToolBase):
|
|
|
97
108
|
|
|
98
109
|
return self._run(profile, runner)
|
|
99
110
|
|
|
111
|
+
@tool_cn_name("应用搜索")
|
|
100
112
|
def app_search(self, *, profile: str, keyword: str = "", page_num: int = 1, page_size: int = 50) -> JSONObject:
|
|
101
113
|
"""Search apps by keyword in name/title using backend search API.
|
|
102
114
|
Useful for finding BUG-related apps across all packages."""
|
|
@@ -136,7 +148,9 @@ class AppTools(ToolBase):
|
|
|
136
148
|
|
|
137
149
|
return self._run(profile, runner)
|
|
138
150
|
|
|
151
|
+
@tool_cn_name("应用详情")
|
|
139
152
|
def app_get(self, *, profile: str, app_key: str) -> JSONObject:
|
|
153
|
+
"""执行应用相关逻辑。"""
|
|
140
154
|
self._require_app_key(app_key)
|
|
141
155
|
|
|
142
156
|
def runner(session_profile, context):
|
|
@@ -196,7 +210,9 @@ class AppTools(ToolBase):
|
|
|
196
210
|
|
|
197
211
|
return self._run(profile, runner)
|
|
198
212
|
|
|
213
|
+
@tool_cn_name("应用基础信息")
|
|
199
214
|
def app_get_base(self, *, profile: str, app_key: str, include_raw: bool = False) -> JSONObject:
|
|
215
|
+
"""执行应用相关逻辑。"""
|
|
200
216
|
self._require_app_key(app_key)
|
|
201
217
|
|
|
202
218
|
def runner(session_profile, context):
|
|
@@ -218,7 +234,9 @@ class AppTools(ToolBase):
|
|
|
218
234
|
|
|
219
235
|
return self._run(profile, runner)
|
|
220
236
|
|
|
237
|
+
@tool_cn_name("更新应用基础信息")
|
|
221
238
|
def app_update_base(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
|
|
239
|
+
"""执行应用相关逻辑。"""
|
|
222
240
|
self._require_app_key(app_key)
|
|
223
241
|
body = self._require_dict(payload)
|
|
224
242
|
|
|
@@ -232,6 +250,7 @@ class AppTools(ToolBase):
|
|
|
232
250
|
|
|
233
251
|
return self._run(profile, runner)
|
|
234
252
|
|
|
253
|
+
@tool_cn_name("应用表单结构")
|
|
235
254
|
def app_get_form_schema(
|
|
236
255
|
self,
|
|
237
256
|
*,
|
|
@@ -243,6 +262,7 @@ class AppTools(ToolBase):
|
|
|
243
262
|
audit_node_id: int | None,
|
|
244
263
|
include_raw: bool = False,
|
|
245
264
|
) -> JSONObject:
|
|
265
|
+
"""执行应用相关逻辑。"""
|
|
246
266
|
self._require_app_key(app_key)
|
|
247
267
|
resolved_form_type = _normalize_form_type(form_type)
|
|
248
268
|
|
|
@@ -271,7 +291,9 @@ class AppTools(ToolBase):
|
|
|
271
291
|
|
|
272
292
|
return self._run(profile, runner)
|
|
273
293
|
|
|
294
|
+
@tool_cn_name("应用编辑版本号")
|
|
274
295
|
def app_get_edit_version_no(self, *, profile: str, app_key: str) -> JSONObject:
|
|
296
|
+
"""执行应用相关逻辑。"""
|
|
275
297
|
self._require_app_key(app_key)
|
|
276
298
|
|
|
277
299
|
def runner(session_profile, context):
|
|
@@ -280,7 +302,9 @@ class AppTools(ToolBase):
|
|
|
280
302
|
|
|
281
303
|
return self._run(profile, runner)
|
|
282
304
|
|
|
305
|
+
@tool_cn_name("应用流程基础信息")
|
|
283
306
|
def app_get_apply_base_info(self, *, profile: str, app_key: str, list_type: int) -> JSONObject:
|
|
307
|
+
"""执行应用相关逻辑。"""
|
|
284
308
|
self._require_app_key(app_key)
|
|
285
309
|
if not isinstance(list_type, int) or isinstance(list_type, bool) or list_type <= 0:
|
|
286
310
|
raise_tool_error(QingflowApiError.config_error("list_type must be a positive integer"))
|
|
@@ -297,7 +321,9 @@ class AppTools(ToolBase):
|
|
|
297
321
|
|
|
298
322
|
return self._run(profile, runner)
|
|
299
323
|
|
|
324
|
+
@tool_cn_name("更新应用流程配置")
|
|
300
325
|
def app_update_apply_config(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
|
|
326
|
+
"""执行应用相关逻辑。"""
|
|
301
327
|
self._require_app_key(app_key)
|
|
302
328
|
body = self._require_dict(payload)
|
|
303
329
|
|
|
@@ -316,7 +342,9 @@ class AppTools(ToolBase):
|
|
|
316
342
|
|
|
317
343
|
return self._run(profile, runner)
|
|
318
344
|
|
|
345
|
+
@tool_cn_name("更新应用表单结构")
|
|
319
346
|
def app_update_form_schema(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
|
|
347
|
+
"""执行应用相关逻辑。"""
|
|
320
348
|
self._require_app_key(app_key)
|
|
321
349
|
body = self._require_dict(payload)
|
|
322
350
|
|
|
@@ -330,7 +358,9 @@ class AppTools(ToolBase):
|
|
|
330
358
|
|
|
331
359
|
return self._run(profile, runner)
|
|
332
360
|
|
|
361
|
+
@tool_cn_name("应用编辑完成")
|
|
333
362
|
def app_edit_finished(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
|
|
363
|
+
"""执行应用相关逻辑。"""
|
|
334
364
|
self._require_app_key(app_key)
|
|
335
365
|
body = self._require_dict(payload)
|
|
336
366
|
|
|
@@ -340,7 +370,9 @@ class AppTools(ToolBase):
|
|
|
340
370
|
|
|
341
371
|
return self._run(profile, runner)
|
|
342
372
|
|
|
373
|
+
@tool_cn_name("创建应用")
|
|
343
374
|
def app_create(self, *, profile: str, payload: JSONObject) -> JSONObject:
|
|
375
|
+
"""执行应用相关逻辑。"""
|
|
344
376
|
body = self._require_dict(payload)
|
|
345
377
|
|
|
346
378
|
def runner(session_profile, context):
|
|
@@ -386,7 +418,9 @@ class AppTools(ToolBase):
|
|
|
386
418
|
|
|
387
419
|
return self._run(profile, runner)
|
|
388
420
|
|
|
421
|
+
@tool_cn_name("删除应用")
|
|
389
422
|
def app_delete(self, *, profile: str, app_key: str) -> JSONObject:
|
|
423
|
+
"""执行应用相关逻辑。"""
|
|
390
424
|
self._require_app_key(app_key)
|
|
391
425
|
|
|
392
426
|
def runner(session_profile, context):
|
|
@@ -399,7 +433,9 @@ class AppTools(ToolBase):
|
|
|
399
433
|
|
|
400
434
|
return self._run(profile, runner)
|
|
401
435
|
|
|
436
|
+
@tool_cn_name("发布应用")
|
|
402
437
|
def app_publish(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
|
|
438
|
+
"""执行应用相关逻辑。"""
|
|
403
439
|
self._require_app_key(app_key)
|
|
404
440
|
body = self._require_dict(payload)
|
|
405
441
|
|
|
@@ -410,10 +446,12 @@ class AppTools(ToolBase):
|
|
|
410
446
|
return self._run(profile, runner)
|
|
411
447
|
|
|
412
448
|
def _require_app_key(self, app_key: str) -> None:
|
|
449
|
+
"""执行内部辅助逻辑。"""
|
|
413
450
|
if not app_key:
|
|
414
451
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
415
452
|
|
|
416
453
|
def _probe_create_access(self, context: BackendRequestContext, app_key: str) -> bool:
|
|
454
|
+
"""执行内部辅助逻辑。"""
|
|
417
455
|
try:
|
|
418
456
|
self.backend.request(
|
|
419
457
|
"GET",
|
|
@@ -428,6 +466,7 @@ class AppTools(ToolBase):
|
|
|
428
466
|
raise
|
|
429
467
|
|
|
430
468
|
def _probe_list_type_access(self, context: BackendRequestContext, app_key: str, list_type: int) -> bool:
|
|
469
|
+
"""执行内部辅助逻辑。"""
|
|
431
470
|
try:
|
|
432
471
|
self.backend.request(
|
|
433
472
|
"POST",
|
|
@@ -442,6 +481,7 @@ class AppTools(ToolBase):
|
|
|
442
481
|
raise
|
|
443
482
|
|
|
444
483
|
def _resolve_accessible_system_views(self, context: BackendRequestContext, app_key: str) -> tuple[list[JSONObject], list[JSONObject]]:
|
|
484
|
+
"""执行内部辅助逻辑。"""
|
|
445
485
|
items: list[JSONObject] = []
|
|
446
486
|
warnings: list[JSONObject] = []
|
|
447
487
|
for view_id, list_type, name in SYSTEM_VIEW_DEFINITIONS:
|
|
@@ -466,6 +506,7 @@ class AppTools(ToolBase):
|
|
|
466
506
|
return items, warnings
|
|
467
507
|
|
|
468
508
|
def _resolve_accessible_custom_views(self, context: BackendRequestContext, app_key: str) -> list[JSONObject]:
|
|
509
|
+
"""执行内部辅助逻辑。"""
|
|
469
510
|
try:
|
|
470
511
|
payload = self.backend.request("GET", context, f"/app/{app_key}/view/viewList")
|
|
471
512
|
except QingflowApiError as exc:
|
|
@@ -491,6 +532,7 @@ class AppTools(ToolBase):
|
|
|
491
532
|
return items
|
|
492
533
|
|
|
493
534
|
def _compact_base_info(self, result: dict[str, Any]) -> JSONObject:
|
|
535
|
+
"""执行内部辅助逻辑。"""
|
|
494
536
|
publish_status = result.get("appPublishStatus")
|
|
495
537
|
auth = result.get("auth") if isinstance(result.get("auth"), dict) else {}
|
|
496
538
|
contact_auth = auth.get("contactAuth") if isinstance(auth, dict) and isinstance(auth.get("contactAuth"), dict) else {}
|
|
@@ -532,6 +574,7 @@ class AppTools(ToolBase):
|
|
|
532
574
|
}
|
|
533
575
|
|
|
534
576
|
def _compact_form_schema(self, result: dict[str, Any]) -> JSONObject:
|
|
577
|
+
"""执行内部辅助逻辑。"""
|
|
535
578
|
base_questions_raw = result.get("baseQues") if isinstance(result.get("baseQues"), list) else []
|
|
536
579
|
form_questions_raw = result.get("formQues") if isinstance(result.get("formQues"), list) else []
|
|
537
580
|
base_questions = [self._compact_question(question) for question in base_questions_raw if isinstance(question, dict)]
|
|
@@ -568,6 +611,7 @@ class AppTools(ToolBase):
|
|
|
568
611
|
}
|
|
569
612
|
|
|
570
613
|
def _compact_user(self, user: Any) -> JSONObject | None:
|
|
614
|
+
"""执行内部辅助逻辑。"""
|
|
571
615
|
if not isinstance(user, dict):
|
|
572
616
|
return None
|
|
573
617
|
return {
|
|
@@ -578,6 +622,7 @@ class AppTools(ToolBase):
|
|
|
578
622
|
}
|
|
579
623
|
|
|
580
624
|
def _compact_tag_item(self, item: dict[str, Any]) -> JSONObject:
|
|
625
|
+
"""执行内部辅助逻辑。"""
|
|
581
626
|
return {
|
|
582
627
|
"itemType": item.get("itemType"),
|
|
583
628
|
"title": item.get("title"),
|
|
@@ -588,6 +633,7 @@ class AppTools(ToolBase):
|
|
|
588
633
|
}
|
|
589
634
|
|
|
590
635
|
def _compact_question(self, question: dict[str, Any]) -> JSONObject:
|
|
636
|
+
"""执行内部辅助逻辑。"""
|
|
591
637
|
options = question.get("options")
|
|
592
638
|
inner_questions = question.get("innerQuestions")
|
|
593
639
|
sub_questions = question.get("subQuestions")
|
|
@@ -610,6 +656,7 @@ class AppTools(ToolBase):
|
|
|
610
656
|
return {key: value for key, value in compact.items() if value is not None}
|
|
611
657
|
|
|
612
658
|
def _extract_visible_apps(self, result: Any) -> tuple[list[JSONObject], str]:
|
|
659
|
+
"""执行内部辅助逻辑。"""
|
|
613
660
|
apps: list[JSONObject] = []
|
|
614
661
|
seen: set[str] = set()
|
|
615
662
|
|
|
@@ -674,6 +721,7 @@ class AppTools(ToolBase):
|
|
|
674
721
|
group_id: int | None,
|
|
675
722
|
group_name: str | None,
|
|
676
723
|
) -> JSONObject | None:
|
|
724
|
+
"""执行内部辅助逻辑。"""
|
|
677
725
|
app_key = str(item.get("appKey") or item.get("app_key") or "").strip()
|
|
678
726
|
if not app_key:
|
|
679
727
|
return None
|
|
@@ -692,6 +740,7 @@ class AppTools(ToolBase):
|
|
|
692
740
|
return {key: value for key, value in compact.items() if value not in (None, [], "", {})}
|
|
693
741
|
|
|
694
742
|
def _count_auth_members(self, auth_payload: Any, member_key: str) -> int:
|
|
743
|
+
"""执行内部辅助逻辑。"""
|
|
695
744
|
if not isinstance(auth_payload, dict):
|
|
696
745
|
return 0
|
|
697
746
|
auth_members = auth_payload.get("authMembers")
|
|
@@ -701,6 +750,7 @@ class AppTools(ToolBase):
|
|
|
701
750
|
return len(members) if isinstance(members, list) else 0
|
|
702
751
|
|
|
703
752
|
def _extract_include_sub_departs(self, auth_payload: Any) -> bool | None:
|
|
753
|
+
"""执行内部辅助逻辑。"""
|
|
704
754
|
if not isinstance(auth_payload, dict):
|
|
705
755
|
return None
|
|
706
756
|
auth_members = auth_payload.get("authMembers")
|