@josephyan/qingflow-cli 0.2.0-beta.985 → 0.2.0-beta.987

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 (44) hide show
  1. package/README.md +2 -2
  2. package/docs/local-agent-install.md +70 -11
  3. package/package.json +1 -1
  4. package/pyproject.toml +1 -1
  5. package/src/qingflow_mcp/__init__.py +1 -1
  6. package/src/qingflow_mcp/builder_facade/service.py +376 -19
  7. package/src/qingflow_mcp/cli/commands/auth.py +14 -43
  8. package/src/qingflow_mcp/cli/commands/workspace.py +8 -5
  9. package/src/qingflow_mcp/cli/formatters.py +19 -22
  10. package/src/qingflow_mcp/config.py +39 -0
  11. package/src/qingflow_mcp/errors.py +2 -2
  12. package/src/qingflow_mcp/public_surface.py +4 -6
  13. package/src/qingflow_mcp/response_trim.py +1 -8
  14. package/src/qingflow_mcp/server.py +1 -1
  15. package/src/qingflow_mcp/server_app_builder.py +4 -28
  16. package/src/qingflow_mcp/server_app_user.py +4 -28
  17. package/src/qingflow_mcp/session_store.py +31 -5
  18. package/src/qingflow_mcp/solution/compiler/form_compiler.py +2 -2
  19. package/src/qingflow_mcp/solution/executor.py +2 -2
  20. package/src/qingflow_mcp/tools/ai_builder_tools.py +117 -1
  21. package/src/qingflow_mcp/tools/app_tools.py +51 -1
  22. package/src/qingflow_mcp/tools/approval_tools.py +82 -1
  23. package/src/qingflow_mcp/tools/auth_tools.py +306 -288
  24. package/src/qingflow_mcp/tools/base.py +204 -4
  25. package/src/qingflow_mcp/tools/code_block_tools.py +21 -0
  26. package/src/qingflow_mcp/tools/custom_button_tools.py +24 -1
  27. package/src/qingflow_mcp/tools/directory_tools.py +28 -1
  28. package/src/qingflow_mcp/tools/feedback_tools.py +8 -0
  29. package/src/qingflow_mcp/tools/file_tools.py +25 -1
  30. package/src/qingflow_mcp/tools/import_tools.py +40 -1
  31. package/src/qingflow_mcp/tools/navigation_tools.py +34 -1
  32. package/src/qingflow_mcp/tools/package_tools.py +37 -1
  33. package/src/qingflow_mcp/tools/portal_tools.py +28 -1
  34. package/src/qingflow_mcp/tools/qingbi_report_tools.py +38 -1
  35. package/src/qingflow_mcp/tools/record_tools.py +255 -2
  36. package/src/qingflow_mcp/tools/repository_dev_tools.py +21 -2
  37. package/src/qingflow_mcp/tools/resource_read_tools.py +23 -1
  38. package/src/qingflow_mcp/tools/role_tools.py +19 -1
  39. package/src/qingflow_mcp/tools/solution_tools.py +56 -1
  40. package/src/qingflow_mcp/tools/task_context_tools.py +72 -1
  41. package/src/qingflow_mcp/tools/task_tools.py +49 -3
  42. package/src/qingflow_mcp/tools/view_tools.py +56 -1
  43. package/src/qingflow_mcp/tools/workflow_tools.py +65 -1
  44. package/src/qingflow_mcp/tools/workspace_tools.py +100 -217
@@ -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")